按数字顺序排序文件

use*_*910 2 java sorting

我制作了一个程序,将文件夹中的所有文件组合在一起.

这是我的代码的一部分:

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的前面.

我希望我能得到可以避免这个问题的高效代码.

ski*_*iwi 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", "")
    );
}
Run Code Online (Sandbox Code Playgroud)

解释pathToInt:

  1. 从给定的Path,获取文件的String表示.
  2. 删除"job"".script".
  3. 尝试将String解析为整数.

解释init,主要方法:

  1. 获取Path文件所在的目录.
  2. Path在目录中获取一个延迟填充的s 列表,请注意:这些Path仍然完全合格!
  3. 保留常规文件的文件.
  4. 保留文件的最后部分Path,因此文件名(例如job1.script)以"job".请注意,您需要首先获取之前的字符串表示形式Path,否则您将检查整个是否以所Path调用的目录开头"job".
  5. 对以".script".结尾的文件执行相同操作.
  6. 现在来了有趣的一点.在这里,我们进行排序基于一个文件列表Comparator,与我们通过调用得到整数比较pathToIntPath.这里我使用方法引用,该方法comparingInt(ToIntFunction<? super T> keyExtractor需要一个函数将a T(在本例中为a)映射Path到int.这正是pathToInt它的作用,因此可以使用方法参考.
  7. 然后我将每个映射PathPath唯一的文件名组成.
  8. 最后,对于每个元素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,因此在代码周围编写包装器是必要的,它决定了如何处理错误.吞下异常很少是一个好主意,我只是在这里使用它来代码简单.

这里真正的重大变化是,不是打印出名称,而是将每个文件映射到其内容并将其写入文件.