我制作了一个程序,将文件夹中的所有文件组合在一起.
这是我的代码的一部分:
File folder = new File("c:/some directory");
File[] listOfFiles = folder.listFiles();
for (File file : listOfFiles){
if (file.isFile()){
System.out.println(file.getName());
File f = new File("c:/some directory"+file.getName());
Run Code Online (Sandbox Code Playgroud)
但是,我希望我的文件可以按照以下顺序:job1.script,job2.script,.....
但我得到:job1.script,job10.script,job11.script,那个10,11,12 ......在2的前面.
我希望我能得到可以避免这个问题的高效代码.
是时候摆脱所有的丛生代码,并使用Java 8!这个答案也是Path该类的特色,它已经是Java 7的一部分,但在Java 8中似乎有了很大的改进.
代码:
private void init() throws IOException {
Path directory = Paths.get("C:\\Users\\Frank\\Downloads\\testjob");
Files.list(directory)
.filter(path -> Files.isRegularFile(path))
.filter(path -> path.getFileName().toString().startsWith("job"))
.filter(path -> path.getFileName().toString().endsWith(".script"))
.sorted(Comparator.comparingInt(this::pathToInt))
.map(path -> path.getFileName())
.forEach(System.out::println);
}
private int pathToInt(final Path path) {
return Integer.parseInt(path.getFileName()
.toString()
.replace("job", "")
.replace(".script", "")
);
}
Run Code Online (Sandbox Code Playgroud)
解释pathToInt:
Path,获取文件的String表示."job"和".script".解释init,主要方法:
Path文件所在的目录.Path在目录中获取一个延迟填充的s 列表,请注意:这些Path仍然完全合格!Path,因此文件名(例如job1.script)以"job".请注意,您需要首先获取之前的字符串表示形式Path,否则您将检查整个是否以所Path调用的目录开头"job".".script".结尾的文件执行相同操作.Comparator,与我们通过调用得到整数比较pathToInt上Path.这里我使用方法引用,该方法comparingInt(ToIntFunction<? super T> keyExtractor需要一个函数将a T(在本例中为a)映射Path到int.这正是pathToInt它的作用,因此可以使用方法参考.Path到Path唯一的文件名组成.Stream<Path>,我打电话System.out.println(Path.toString()).看起来这段代码可能更容易编写,但是我故意写得更详细.我在这里的设计是保持完整Path完好时刻,在代码的最后一部分forEach实际上违反了作为前不久被映射到唯一的文件名,因此你无法处理完整的原则,Path再在稍后一点.
此代码也设计为快速失败,因此它期望文件在表单中存在job(\D+).script,并且NumberFormatException如果不是这样的话将抛出.
示例输出:
job1.script
job2.script
job10.script
job11.script
Run Code Online (Sandbox Code Playgroud)
一个可以说是更好的选择具有正则表达式的强大功能:
private void init() throws IOException {
Path directory = Paths.get("C:\\Users\\Frank\\Downloads\\testjob");
Files.list(directory)
.filter(path -> Files.isRegularFile(path))
.filter(path -> path.getFileName().toString().matches("job\\d+.script"))
.sorted(Comparator.comparingInt(this::pathToInt))
.map(path -> path.getFileName())
.forEach(System.out::println);
}
private int pathToInt(final Path path) {
return Integer.parseInt(path.getFileName()
.toString()
.replaceAll("job(\\d+).script", "$1")
);
}
Run Code Online (Sandbox Code Playgroud)
这里我使用正则表达式"job\\d+.script",它匹配以"job"字母开头的字符串,后跟一个或多个数字,后跟".script".
我对该pathToInt方法使用几乎相同的表达式,但是我使用捕获组,括号,并$1使用该捕获组.
我还将提供一种简洁的方法来读取一个大文件中的文件内容,因为您在问题中也提到了:
private void init() throws IOException {
Path directory = Paths.get("C:\\Users\\Frank\\Downloads\\testjob");
try (BufferedWriter writer = Files.newBufferedWriter(directory.resolve("masterjob.script"))) {
Files.list(directory)
.filter(path -> Files.isRegularFile(path))
.filter(path -> path.getFileName().toString().matches("job\\d+.script"))
.sorted(Comparator.comparingInt(this::pathToInt))
.flatMap(this::wrappedLines)
.forEach(string -> wrappedWrite(writer, string));
}
}
private int pathToInt(final Path path) {
return Integer.parseInt(path.getFileName()
.toString()
.replaceAll("job(\\d+).script", "$1")
);
}
private Stream<String> wrappedLines(final Path path) {
try {
return Files.lines(path);
} catch (IOException ex) {
//swallow
return null;
}
}
private void wrappedWrite(final BufferedWriter writer, final String string) {
try {
writer.write(string);
writer.newLine();
} catch (IOException ex) {
//swallow
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,lambdas不能抛出/捕获已检查的Exceptions,因此在代码周围编写包装器是必要的,它决定了如何处理错误.吞下异常很少是一个好主意,我只是在这里使用它来代码简单.
这里真正的重大变化是,不是打印出名称,而是将每个文件映射到其内容并将其写入文件.