Java:递归模式搜索要作为变量传递的文件(具有相对路径)



。。。认为这会很简单…:/

我需要从工作目录中递归搜索(我可以找到)与模式匹配的文件,然后将每个文件作为输入传递给缓冲区恐惧器。

到目前为止,我还没能很好地计算出路径、文件和字符串之间的类型匹配,以便在函数之间传递值。。。

Lil背景:此程序将根据年份和州移动到不同的文件夹,以将文本文件解析为表格格式进行数据QA。我的文本文件解析代码运行良好,但需要自动获取州内每个县的日志文件。

我实现了查找当前工作目录的代码:

File workingDir = new File(new File(".").getAbsolutePath());
Path workDir = Paths.get(workingDir.getCanonicalPath());

我两者都得到了,因为我还没有取得足够的进步,不知道我到底需要哪一个。。。

我(非常感谢!!)能够递归地从工作目录中找到所有文件:

Files.find(Paths.get(workDir.toString()),
Integer.MAX_VALUE,
(filePath, fileAttr) -> fileAttr.isRegularFile())
.forEach(System.out::println);

我一直不知道如何为我想要的文件传递过滤器;或者如何将文件放入一个可迭代列表中,作为bufferedreader的输入文件列表传递。

//List of input files for bufferedreader:
java.util.List<String> inputFiles = new ArrayList<String>();

然后将"Files.fund(paths…"块更改为:

.forEach(inputFiles.add());

不起作用。我不知道该把什么作为论据,而且。。。inputFiles.add()'在没有参数的情况下无法编译(JDK 10)。

我尝试了一个PathMatcher,但不知道如何键入匹配我传递给它的函数,这样代码就可以编译了。

这是我的模式,在标准正则表达式中:

Pattern logFile = Pattern.compile("Correct_[\d]{4}-[\d]{2}-[\d]{2}_[\d]{2}-[\d]{2}.txt");

该模式翻译为:"Correct_yyyy-MM-dd_HH-MM.txt"。

我无法编译以下内容,在".collect(Collectors.toList());"中的"Collector"上出现".java:87:错误:找不到符号":

inputFiles = Files.walk(Paths.get(workDir.toString()))
.filter(Files::isRegularFile)
.map(Path::toFile)
.collect(Collectors.toList());

我导入了java.io.、java.io.File.、java.nio.*&java.nio.file.*。

很明显,我不懂file.io/file.nio,在阅读了Oracle文档/教程以及众多SO和其他论坛/网站后,我一直无法生成工作代码。

有人能给我指正确的方向吗?

非常感谢!

您报告的原始问题是java:87: error: cannot find symbol" on 'Collector' in ".collect(Collectors.toList());。看看这个错误,问题已经很清楚了——您没有在代码中导入java.util.stream.Collectors

但一旦导入,就会出现另一个问题——java:88: error: incompatible types: inference variable T has incompatible bounds .collect(Collectors.toList());。这通常意味着蒸汽不能产生你需要的类型。您需要inputFiles的值,该值的类型为List<String>。您得到的集合是List<File>,因为您之前在映射中使用Path.toFile()。我建议您删除映射(将其保留为路径列表)或将inputFiles更改为List<File>

顺便说一句,你可以在这篇文章中看到如何处理这个错误,例如:java:不兼容类型:推理变量T有不兼容的边界。

一般来说,最好一次调试一个编译错误,只需在SO中查找引用您所得到的错误的帖子。这种过程可能是迭代的,需要一些时间。

没有发现任何演练,但许多例子缺乏对WHY&如何使用regex运行递归文件搜索并将结果传递给变量,我写了一个:

我是个新手。有很多我不知道或完全理解。我在这篇文章中介绍了我所知道的的最新情况-请理解,在撰写本文时"我所知道"可能是错误的,而且是不完整的。话虽如此,我们非常欢迎更正!非常感谢。

我的程序旨在移动到父文件夹,并运行以从子文件夹获取文件,因此它可能需要知道其工作目录。不幸的是,没有(我发现的)非技巧性的方法可以实现这一点。

以下两行代码将为您提供Java应用程序工作目录的路径-注意:这个应该是执行应用程序的位置。

请记住导入相应的库。我正在学习Java,所以对学习任何人喜欢的附加库都不感兴趣,所以我只使用Oracle Java库。稍后,当我熟练掌握Java开发时,我将开始学习插件的酷炫功能。

import java.io.*;
import java.io.File.*;
import java.nio.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
import static java.nio.file.FileVisitResult.*;
import static java.nio.file.FileVisitOption.*;
import java.util.*;
import java.util.stream.*;
import java.util.regex.*;

注意:如果您从SO或其他在线资源中获取的方法出现"找不到符号"或编译时错误,则可能您没有导入正确的库。。。问我怎么知道的。)

有几种方法可以获得工作目录,但因为我需要将工作目录传递给另一个使用File、Path、FileSystems等的函数,所以我想使用"兼容"的东西。这显然不是一件事。

File workingDir = new File(new File(".").getAbsolutePath());
Path workDir = Paths.get(workingDir.getCanonicalPath());

第一行标识可以创建"新文件"的位置,然后获取该潜在文件的绝对路径。文件名是"."-这可能有点令人困惑。。。

第二行将文件"."的绝对路径(不包括文件名)指定给变量。路径从根目录开始(即Windows环境中的驱动器号)。关于绝对、规范路径的更多信息,可以在下面的2/3找到:绝对/规范路径描述

现在我的应用程序知道它在哪里了,我需要一个可迭代的对象来传递条目——这是匹配我的regex的文件将被传递到的变量:

java.util.List<String> files = new ArrayList<>();

注意:我必须在"List"声明中包含"java.util.",因为我导入了其他库,如果没有它,这些库会使声明变得不明确。这些代码都不相关,因此不包含在内。

现在,进入递归搜索。再说一次,没有一种非技巧性的方法可以做到这一点。我想这会很常见,以至于会开发出一个干净的方法来实现这一点——我的意思是,我知道至少有三种不同的方法来编写"for"循环!-但我想这反映了Oracle开发Java的人员使用Java的更多内容,而不仅仅是"用户"(我们)对产品的使用。

我选择使用PathMatcher是因为我还需要指定不搜索文件的文件夹。"Files.find()"和许多有才华的人试图编程的类并没有那么简单的方法来实现这一点。

final PathMatcher matcher = FileSystems.getDefault().getPathMatcher("regex:.*Correct_\d{4}-\d{2}-\d{2}_\d{2}-\d{2}\.txt");
Files.walkFileTree(Paths.get(workDir.toString()), new SimpleFileVisitor<Path>() 
{
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException
{
if (dir.getFileName().toString().equals("Reprocess"))
{
return SKIP_SUBTREE;
}
return CONTINUE;
}//end public preVisitDirectory
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException 
{
if (matcher.matches(file))
{
files.add(file.toString());
}//end if(matcher)
return FileVisitResult.CONTINUE;
}//end visitFile
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException 
{
return FileVisitResult.CONTINUE;
}//end visitFileFailed
});//end Files.walkFileTree1

我的代码上有几个注释:1。作为一名新手程序员,我发现跟踪我的大括号来标记每个大括号属于谁是很有帮助的;2.我的正则表达式是高度特定的,因为我正在搜索程序化输出——每次都是一样的。

PathMatcher声明:Final指示Java这不会改变。'FileSystem.getDefault()'标识操作系统,以便斜线指向正确的方向(以及其他内容)getPathMatcher('执行一个类似Pattern.compile()的函数。

"regex:"将搜索定义为"regex",而不是"glob"搜索。我打断了这一行,因为在这种情况下很难找到regex语法的示例。

关于我的特定regex模式的另一个注意事项是:如果没有".*",它就不起作用,".*"表示"前面的任何数量的字符"-我的假设是,这说明了工作目录被添加为搜索匹配的每个文件的绝对路径。。。我花了一段时间才弄清楚为什么工作中的regex(我在粘贴了一些文件名的缓冲区中进行了测试)没有返回结果。

Files.walkFileTree:执行Files类的"walkFileTree"方法,将"Paths.get("作为参数。"Paths.get("将我们以前建立的工作目录作为参数。

早些时候,我提到在文件、路径和;文件系统不是什么东西。好吧,以我目前的技能水平,我能传递一个"List"对象作为Path信息的唯一方法是首先将其作为字符串对象。所以,我们有了"workDir.toString()"。在我的工作目录路径中进行硬编码也很有效,仅供参考。

注意:".."指定了Java应用程序执行位置的相对路径。这就是为什么我早些时候说我的程序">可能"需要知道它的工作目录——事实证明我的不知道,但你的可能知道。我使用我的变量来保存我的工作目录的绝对路径(对我的代码执行没有明显的影响)。如果您只想要一个相对的路径位置,可以传入".."(包括双引号)而不是"workDir.toString()"。

new SimpleFileVisitor:一个简单文件访问者的实例。

第一个参数指定"preVisitDirectory"指令;这是我指示程序不要在"重新处理"文件夹中搜索的地方。如果需要的话,可以在这里插入许多其他说明。

第二个参数指定我的程序在找到匹配项时应该做什么——在这种情况下,匹配项被添加到"files"ArrayList中。

第三个参数指示程序在找不到匹配项时不要着急。

结束。

嗯,不是真的,但这段代码确实使用regex执行递归文件搜索,并将匹配项输出到变量(本例中为ArrayList)。

以一种可行的格式重新输出文件名也是一件苦差事。我确信这是因为我将ArrayList定义为String而不是File(或者其他noob错误,或者三个…)

祝你好运!如果您有任何问题、意见或担忧,请随时联系我(如果有)。

Jake

更新:我能够弄清楚如何将文件名传递到FileInputStream中。更改,如下:

java.util.List<String> files = new ArrayList<>();

变成:

java.util.List<File> files = new ArrayList<>();

"Files.walkFileTree"函数中的visitRule参数变为:

public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException 
{
if (matcher.matches(file))
{
files.add(file.toFile());
//'files.add(file.toString());' changed
}//end if(matcher)

添加以下代码是为了将"files"ArrayList转换为fileArray,Array,然后在运行时将Array中的每个元素转换为字符串,并将该字符串传递给FileInputStream(封装在BufferedReader中)。

int fLength = files.size();
File[] fileArray = files.toArray(new File[fLength]);
for(int f=0; f<files.size(); f++)
{
//log file Reader init:
String corrFile = fileArray[f].toString();
BufferedReader corrReader = new BufferedReader(new InputStreamReader(new FileInputStream(corrFile),"UTF-16LE"));
//NOTE: PFO differential correction log files are encoded in UTF-16 LE

啊,这是一个包裹!我的项目的这一方面是完整的,并且工作正常。

最新更新