在 Java 中,简单地计算文件数量变得异常困难。
我想指向一个文件夹,并计算在该文件夹顶层找到的文件数。忽略隐藏文件,例如以
.
开头的 Unix 风格名称。忽略嵌套文件夹。
示例:
📂 Sales
📂 Wine Sales 2024
📄 Interim report.text
📂 Q1
📄 West region.text
📄 East region.text
📂 Q2
📂 Q3
📂 Q4
如果我指向名为“Wine Sales 2024”的文件夹,我想获得
1
的计数,以获取直接在该文件夹中找到的文件的计数。在这种情况下,Interim report.text
。我想忽略其中的文件夹。我确实不想要对这些嵌套文件夹中找到的任何文档进行递归计数。
File#listFiles
我找到了问题,使用Java计算目录中的文件数量。但那个Question其实是在问性能问题,而我并不关心性能问题。我有一些简单的文件夹,其中可能有十几个文档;我只是想要一种简单的方法来获得计数。
该问题有一些不符合我的基本标准的尴尬代码。这一行:
new File(<directory path>).listFiles().length
…例如:
final int countFilesFound = Objects.requireNonNull( path.toFile( ).listFiles( ( folder , name ) -> !name.startsWith( "." ) ) ).length;
...有一些问题:
( folder , name ) -> !name.startsWith( "." )
,它确实有效。Path
对象转换为 File
才能完成这项工作,这对我来说似乎很愚蠢,但没什么大不了的。Files.list
这个答案显示了使用 Java 8+ 的 Java NIO 功能的代码。
try (Stream<Path> files = Files.list(Paths.get("your/path/here"))) {
long count = files.count();
}
我将其改编为部分解决方案:
final long count;
try
{
count = Files.list( path ).filter( Files :: isRegularFile ).count( );
}
catch ( IOException e )
{
throw new RuntimeException( e );
}
问题包括:
.list
调用在我的 IDE 中发出警告,提示我需要在此处尝试使用资源。我无法理解需要在具有终端操作的流上调用 close
(此处为.count
)。我在使用流的所有时间里从未见过这个问题。是否有任何简单的方法来获取直接在文件夹中找到的真实文件的列表和/或计数?
你不能真正逃避这里的异常处理(除非API像旧的那样吞下异常),对文件和文件夹的操作总是会失败。
从技术上讲,你无法使用 lomboks
@SneakyThrows
或类似的东西来处理异常,但最好处理它,IOException
是一种真正的可能性。
docs明确指出,必须关闭源为 IO 通道的流:
Streams 有一个 BaseStream.close() 方法并实现 AutoCloseable,但几乎所有流实例在使用后实际上并不需要关闭。通常,只有源是 IO 通道的流(例如由 Files.lines(Path, Charset) 返回的流)才需要关闭。大多数流由集合、数组或生成函数支持,不需要特殊的资源管理。 (如果流确实需要关闭,则可以在 try-with-resources 语句中将其声明为资源。)
最好的选择是尝试使用资源来关闭流并一起处理异常:
final long count;
try (Stream<Path> stream = Files.list(Path.of("some path"))) {
count = stream
.peek(path -> System.out.println("debug current path - " + path))
.filter(Files::isRegularFile)
.count();
System.out.println(count);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
您可以将旧的 API 与流结合起来,以便不处理异常,但这可能不是一个好主意,因为它会被吞没,所有 File.listFiles() 方法都会这样做:
退货: 抽象路径名数组,表示此抽象路径名表示的目录中的文件和目录。如果目录为空,则数组将为空。如果此抽象路径名不表示目录,或者发生 I/O 错误,则返回 null。
final long countFilesFound = Arrays.stream(Objects.requireNonNull(path.toFile().listFiles((folder, name) -> !name.startsWith("."))))
.filter(File::isFile)
.count();
而且,恕我直言,这种方法的可读性较差。