我制作了一个程序,将文件夹中的所有文件组合在一起。
这是我的代码的一部分:
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());
但是,我希望我的文件可以按顺序排列: job1.script,job2.script,.....
但我明白了: job1.script,job10.script,job11.script,那个10,11,12 ...都在2的前面。
我希望我能够获得可以避免此问题的高效代码。
答案 0 :(得分:6)
时间摆脱所有丛生代码,并使用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", "")
);
}
pathToInt
的解释:
Path
获取文件的字符串表示。"job"
和".script"
。 init
的解释,主要方法:
Path
。Path
添加的懒惰填充列表,请注意:这些Path
仍然完全合格!Path
的最后部分的文件,因此文件名(例如job1.script
)以"job"
开头。 请注意您需要首先获取Path
的字符串表示形式,然后才能检查它,否则您将检查整个Path
是否以名为{的目录开头{1}}。"job"
结尾的文件执行相同操作。".script"
对文件列表进行排序,该Comparator
通过调用pathToInt
上的Path
来比较我们获得的整数。这里我使用方法引用,方法comparingInt(ToIntFunction<? super T> keyExtractor
期望一个函数将T
(在本例中为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
一个可以说是更好的替代方案具有正则表达式的强大功能:
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")
);
}
这里我使用正则表达式"job\\d+.script"
,它匹配以"job"
开头的字符串,后跟一个或多个数字,后跟&#34; .script&#34;。
我对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
}
}
请注意,lambdas不能抛出/捕获已检查的Exception
,因此在代码周围编写包装器是必要的,它决定了如何处理错误。吞下异常很少是一个好主意,我只是在这里使用它来代码简单。
这里真正的重大变化是,不是打印出名称,而是将每个文件映射到其内容并将其写入文件。
答案 1 :(得分:2)
如果您的文件名称始终为jobNumber.script
,则可以对提供自定义比较器的array
进行排序:
Arrays.sort(listOfFiles, new Comparator<File>(){
@Override
public int compare(File f1, File f2) {
String s1 = f1.getName().substring(3, f1.getName().indexOf("."));
String s2 = f2.getName().substring(3, f2.getName().indexOf("."));
return Integer.valueOf(s1).compareTo(Integer.valueOf(s2));
}
});
public static void main(String[] args) throws Exception{
File folder = new File(".");
File[] listOfFiles = folder.listFiles(new FilenameFilter() {
@Override
public boolean accept(File arg0, String arg1) {
return arg1.endsWith(".script");
}
});
System.out.println(Arrays.toString(listOfFiles));
Arrays.sort(listOfFiles, new Comparator<File>(){
@Override
public int compare(File f1, File f2) {
String s1 = f1.getName().substring(3, f1.getName().indexOf("."));
String s2 = f2.getName().substring(3, f2.getName().indexOf("."));
return Integer.valueOf(s1).compareTo(Integer.valueOf(s2));
}
});
System.out.println(Arrays.toString(listOfFiles));
}
打印:
[.\job1.script, .\job1444.script, .\job4.script, .\job452.script, .\job77.script]
[.\job1.script, .\job4.script, .\job77.script, .\job452.script, .\job1444.script]
答案 2 :(得分:1)
最简单的解决方案是将所有低于10的数字填零。如
job01.script
而不是
job1.script
这假设不超过100个文件。使用更多,只需添加更多零。
否则,您需要分析并细分每个文件名,然后按数字对其进行排序。目前,它是由字符订购的。
答案 3 :(得分:0)
解决此问题的最简单方法是在名称前添加0
s。这就是我遇到同样问题时的所作所为。所以基本上你选择你拥有的最大数字(例如433234
)并在所有数字前加biggestLength - currentNumLength
个零。
一个例子:
最大号码为12345
:job12345.script
。
这样第一份工作就变成了job00001.script
。