java.io: 重命名绝对文件路径的所有元素
java.io: Rename all elements of an absolute File path
我正在为 "normalizing" 文件名和目录名编写一个小工具,使它们在可移植性、互操作性和普遍减少由于文件名具有 non-ASCII 个字符、空格而导致的愚蠢和痛苦错误方面是安全的和其他邪恶角色等(请参阅 this SuperUser answer 了解少数真正安全角色的简明摘要)。
为此,我想将名称不安全的 file/directory 重命名为安全名称, 包括 相应地重命名所有 parent 目录。应该不是问题,即使我需要使用 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)
前两关,全部改名;突然达到叶子文件的盛大parent, renameTo()
returns 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 ÄÖÜßéÂÌ\.bad folder 2\test filename-ÄÖÜ.txt
作为基本路径,unsafeParent
等于 \test\-bad.folder NAME ÄÖÜßéÂÌ\.bad folder 2
,但 safeTarget
现在是 unsafeParent + safe.getName()
,所以你不是试图重命名目录,但 unsafeParent
中的一个文件名为 safe.getName()
...
不是自下而上,而是自上而下。这意味着您可以重命名目录并使用重命名的引用,列出其中的文件并处理它们。
我正在为 "normalizing" 文件名和目录名编写一个小工具,使它们在可移植性、互操作性和普遍减少由于文件名具有 non-ASCII 个字符、空格而导致的愚蠢和痛苦错误方面是安全的和其他邪恶角色等(请参阅 this SuperUser answer 了解少数真正安全角色的简明摘要)。
为此,我想将名称不安全的 file/directory 重命名为安全名称, 包括 相应地重命名所有 parent 目录。应该不是问题,即使我需要使用 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)
前两关,全部改名;突然达到叶子文件的盛大parent, renameTo()
returns 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 ÄÖÜßéÂÌ\.bad folder 2\test filename-ÄÖÜ.txt
作为基本路径,unsafeParent
等于 \test\-bad.folder NAME ÄÖÜßéÂÌ\.bad folder 2
,但 safeTarget
现在是 unsafeParent + safe.getName()
,所以你不是试图重命名目录,但 unsafeParent
中的一个文件名为 safe.getName()
...
不是自下而上,而是自上而下。这意味着您可以重命名目录并使用重命名的引用,列出其中的文件并处理它们。