java.io : Rename all elements of an absolute File path

标签 java io directory file-rename

我正在编写一个小工具,用于“规范化”文件和目录名称,使它们能够安全地实现可移植性、互操作性,并普遍减少由于文件名包含非 ASCII 字符、空格和其他邪恶字符等而导致的愚蠢和痛苦的错误。 (有关少数真正安全字符的简明摘要,请参阅 this SuperUser answer)。

为此,我想将具有不安全名称的文件/目录重命名为安全名称,包括相应地重命名所有父目录。即使我需要使用 java.io,也不应该成为问题;但是我似乎无法重命名包含其他目录的目录(包含文件工作正常)。

这是我的方法:

public static File renameSafe(File unsafe) throws IOException {
    if (!unsafe.exists()) {
        throw new FileNotFoundException(unsafe.toString());
    }

    // create full "safe" path
    File safe = toSafeFile(unsafe);
    File origSafe = safe;

    while (unsafe != null) {
        // rename the lowest unsafe level
        File unsafeParent = unsafe.getParentFile();
        File safeTarget = new File(unsafeParent, safe.getName());
        if (!unsafe.renameTo(safeTarget)) {
            throw new IOException("Could not rename " + unsafe + " to " + safe);
        }

        unsafe = unsafeParent;
        safe = safe.getParentFile();
    }

    return origSafe;
}

当我运行这个主要方法时:

public static void main(String[] args) throws IOException {
    File file = new File("\\test\\-bad.folder NAME ÄÖÜßéÂÌ\\.bad folder 2\\test filename-ÄÖÜ.txt");
    System.out.println(file);
    System.out.println(toSafeFileName(file));
    renameSafe(file);
}

我得到以下输出:

\test\-bad.folder NAME ÄÖÜßéÂÌ\.bad folder 2\test filename-ÄÖÜ.txt
\test\_bad_folder_name_aou-eai\_bad_folder_2\test_filename-aou.txt
Exception in thread "main" java.io.IOException: Could not rename \test\-bad.folder NAME ÄÖÜßéÂÌ to \test\_bad_folder_name_aou-eai
    at SafeFileName.renameSafe(SafeFileName.java:77)
    at SafeFileName.main(SafeFileName.java:90)

前两关,一切都按原样重命名;到达叶文件的祖父文件时,renameTo() 突然返回 false

所以我的问题是,我做错了什么?我尝试使用其他文件名(包括 100% 输入文件名),但似乎 File.renameTo() 似乎无法重命名包含其他目录的目录。然而,我个人的赌注是我自己的一些愚蠢行为,再加上一些晦涩的 API 细节。

编辑:

好的,这是 SSCCE:

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

public class RenameTest
{
    public static File toSafeFileName(File file) {
        File safe = new File(file.getName().replace("bad", "good"));

        for (;;) {
            file = file.getParentFile();
            if (file == null) {
                return safe;
            }

            if (file.toString().equals(File.separator)) {
                safe = new File("", safe.getPath());
            } else {
                safe = new File(
                        file.getName().replace("bad", "good"),
                        safe.getPath());
            }
        }
    }

    public static File renameSafe(File unsafe) throws IOException {
        if (!unsafe.exists()) {
            throw new FileNotFoundException(unsafe.toString());
        }

        File safe = toSafeFileName(unsafe);
        File origSafe = safe;

        while (unsafe != null && !unsafe.equals(safe)) {
            File unsafeParent = unsafe.getParentFile();
            File safeTarget = new File(unsafeParent, safe.getName());

            System.out.print(unsafe + " -> " + safeTarget + "? ");

            if (unsafe.renameTo(safeTarget)) {
                System.out.println("OK.");
            } else {
                System.out.println("Error!");
                throw new IOException();
            }

            unsafe = unsafeParent;
            safe = safe.getParentFile();
        }

        return origSafe;
    }

    public static void main(String[] args) throws IOException {
        File unsafePath = new File("\\test\\bad1\\bad2\\bad.txt");
        if (!unsafePath.getParentFile().mkdirs()) {
            throw new IOException("can't create " + unsafePath.getParentFile());
        }
        if (!unsafePath.createNewFile()) {
            throw new IOException("can't create dummy file");
        }

        File safePath = renameSafe(unsafePath);
        if (safePath.exists()) {
            System.out.println("Renamed " + unsafePath + " to " + safePath);
        } else {
            throw new IOException("Safe path " + safePath + " does not exist.");
        }
    }
}

首次运行时,使用干净的 D:\test 目录,一切运行正常:

\test\bad1\bad2\bad.txt -> \test\bad1\bad2\good.txt? OK.
\test\bad1\bad2 -> \test\bad1\good2? OK.
\test\bad1 -> \test\good1? OK.
Renamed \test\bad1\bad2\bad.txt to \test\good1\good2\good.txt

好吧,Java可以重命名包含目录的目录。

但是,在第二次运行时(没有先清理 D:\test),我得到以下结果:

\test\bad1\bad2\bad.txt -> \test\bad1\bad2\good.txt? OK.
\test\bad1\bad2 -> \test\bad1\good2? OK.
\test\bad1 -> \test\good1? Error!
Exception in thread "main" java.io.IOException
    at funky.core.io.RenameTest2.renameSafe(RenameTest2.java:46)
    at funky.core.io.RenameTest2.main(RenameTest2.java:65)

所以看起来问题确实是我没有清理我的测试目录,并且 Java 无法将目录重命名为已经存在的目录 - 因为 good1 已经创建了第一次运行时...正如 renameTo() API 中所述,这确实只是我自己的愚蠢行为。抱歉浪费您的时间。

最佳答案

对我来说,这...

File unsafeParent = unsafe.getParentFile();
File safeTarget = new File(unsafeParent, safe.getName());

因此,使用 \test\-bad.folder NAME äÖÜßéÂÌ\.badfolder 2\test filename-äÖÜ.txt 作为基本路径,unsafeParent 将等于 \test\-bad.folder NAME äÖÜßéÂÌ\.badfolder 2,但 safeTarget 现在是 unsafeParent + safe.getName(),所以你'我不是在尝试重命名该目录,而是在 unsafeParent 中重命名一个名为 safe.getName()...

不要自下而上工作,而是自上而下工作。这意味着您可以重命名目录并使用重命名的引用,列出其中的文件并处理它们。

关于java.io : Rename all elements of an absolute File path,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31601124/

相关文章:

java - 在 Java 中将外部 XML 解析为 JSON?

c# - 在 C# 中将目录 NAME 设为只读

c# - 如何删除子目录

c# - 在复制和粘贴时查找丢失的文件和子目录及其文件列表?

python 2.5 : IO module

directory - 使用 AutoHotkey 读取目录中的文件名

java - 将 Spring MVC 应用程序从 JSP 迁移到 AngularJS

java - 如何将 JPanel 变成 BufferedImage Java

java - 我需要为偶数和赔率得到两条单独的线,但要注意的是,我只能使用一个 while 循环

c - 用C写shell,如何区分交互模式和批处理模式