Java中针对包含西里尔字母字符的文件路径发生java.io.filenotfoundexception异常

17

我有一个文件名包含不仅是普通 ASCII 字符集的字符,而且还包括非 ASCII 字符集中的字符。在我的情况下,它包含 Cyrillic 字符。

以下是我的代码片段:

String fileName = "/Users/dnelepov/Downloads/тест изображение.png";
File sendFile = new File(fileName);
if (sendFile.exists()) {
    // Some code
}

sendFile.exists 中的代码块没有被执行。

为什么文件没有被识别?

我的系统配置locale

LANG="ru_RU.UTF-8"
LC_COLLATE="ru_RU.UTF-8"
LC_CTYPE="ru_RU.UTF-8"
LC_MESSAGES="ru_RU.UTF-8"
LC_MONETARY="ru_RU.UTF-8"
LC_NUMERIC="ru_RU.UTF-8"
LC_TIME="ru_RU.UTF-8"
LC_ALL="ru_RU.UTF-8"

uname -a

Darwin Dmitrys-MacBook-Pro.local 11.4.2 Darwin Kernel Version 11.4.2: Thu Aug 23 16:25:48 PDT 2012; root:xnu-1699.32.7~1/RELEASE_X86_64 x86_64

java -version

java version "1.7.0_21"
Java(TM) SE Runtime Environment (build 1.7.0_21-b12)
Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)

更新

我发现这个错误是由Oracle的JDK引起的。

我在Eclipse上创建了项目,并找到了文件。我检查了项目属性,发现使用的是Mac OS 6 JDK。

然后我将它更改为JDK 7,但文件又再次找不到了。

我的问题是我需要使用带有JavaFX的JDK 7,而不是Mac OS版本。所以我的问题仍然存在。

我制作了一个视频来展示这个错误 包含错误的视频

更新2

感谢eumust提供的答案,这段代码有效:

Path path = Paths.get("/Users/dnelepov/Downloads/test/");
    Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
        @Override
        public FileVisitResult visitFile(Path oneF, BasicFileAttributes attrs) throws IOException {
            System.out.println("FILE:" + oneF);
            if (Files.exists(oneF)) {
                System.out.println("EXISTS:" + oneF);
            }
            return FileVisitResult.CONTINUE;
        }
    });

https://dev59.com/S3PYa4cB1Zd3GeqPeQpy#17481204


2
我猜这是Mac OS X? - fge
是的,这让我感到非常痛苦 :( - Dmitry Nelepov
添加视频展示问题。 - Dmitry Nelepov
文件 f = Paths.get(fileName).toFile(); - 是的,文件未找到。 - Dmitry Nelepov
你检查过JVM内部的系统属性"file.encoding"在不同的Java版本中是否相同了吗? - Panu
显示剩余6条评论
4个回答

5

仅供娱乐,这个hack可能会起作用:

String fDir = "/Users/dnelepov/Downloads/";
char[] fileName = "тест изображение.png".toCharArray();
File root = new File(fDir);
File[] folder = root.listFiles();

for (File f : folder) 
    if (Array.equals(fileName, f.getName().toCharArray()) {
        //code here
          ...
    }

我不确定这对你是否会产生任何不同的结果,尤其是因为可能只是文件名的奇怪编码问题,但这可能会有助于阐明情况。如果代码没有执行,请针对目录中所有文件名的charArray打印int(ascii vals) - 找到您要查找的文件并查看字符是如何编码的以及为什么它们不相等。


这似乎是一种不错的方法,可以检查它是否能读取目录中所有文件的名称。对于每个文件,我会将结果输出到错误日志,并将该字符串与您正在使用的实际文件名进行比较,以查找差异。然后,您将能够以某种方式处理此错误 - 我猜最终您将从用户交互中获取此文件?如果不是,您可以重命名文件吗?您可以获取指向其物理位置、大小等的指针,然后读入内容吗?还是这不可能,我在胡说八道? - DaveM

2
以下代码在使用Java 7 b21和OSX 10.8.4时,在OSX上输出true。根据您的内核版本,看起来您正在使用10.7。
import java.io.File;

public class file {
    public static void main(String[] args) {
        File file = new File("/Users/jhawk28/Developer/filetest/тест изображение.txt");
        System.out.println(file.exists());
    }
}

根据您提供的项目,这是我机器上的输出结果:

java -jar TestCyrilic.jar 
EX:true

看起来这是在OSX 10.8中修复的一个错误。


OSX:Darwin Dmitrys-MacBook-Pro.local 11.4.2 Darwin Kernel Version 11.4.2: Thu Aug 23 16:25:48 PDT 2012; root:xnu-1699.32.7~1/RELEASE_X86_64 x86_64
Java:java version "1.7.0_21" Java(TM) SE Runtime Environment (build 1.7.0_21-b12) Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)
Locale: LANG="ru_RU.UTF-8" LC_COLLATE="ru_RU.UTF-8" LC_CTYPE="ru_RU.UTF-8" LC_MESSAGES="ru_RU.UTF-8" LC_MONETARY="ru_RU.UTF-8" LC_NUMERIC="ru_RU.UTF-8" LC_TIME="ru_RU.UTF-8" LC_ALL="ru_RU.UTF-8"
- Dmitry Nelepov
也许你应该使用带有操作系统和JDK的虚拟机,它会更加可预测。 - Maxim Kolesnikov

2
我用Unicode 等价字符替换了 Cyrillic 字符,对我来说似乎有效:
String fileName = "/Users/user1/тест \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435.txt";

尝试一下。

字符串 fileName = "/Users/dnelepov/Downloads/test/\u0442\u0435\u0441\u0442\u0020\u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435.png"; System.out.println("EX:" + new File(fileName).exists()); - 结果 EX:false - Dmitry Nelepov

2

我遇到了非ASCII字符的相同问题,这个方法可以帮助解决(已更新):

String fileName = "file:///Users/dnelepov/Downloads/тест изображение.png"; 
URI uri = new URI(null, null, fileName, null); 
System.out.println("TS:" + uri.getPath);
System.out.println("EX:" + new File(uri).exists());

字符串 fileName = "/Users/dnelepov/Downloads/тест изображение.png"; 字符串 ts = new URI(fileName).getPath(); System.out.println("TS:" + ts); 结果:异常 java.net.URISyntaxException: 路径中的非法字符索引为30:/Users/dnelepov/Downloads/тест изображение.png - Dmitry Nelepov
1
尝试使用 new URI(null, null, yourPath, null) - fge
1
问题出在空格上,所以你可以用 %20 替换它,或者使用 @fge 的解决方案。我也会更新答案。 - Balint Bako
Balint Bako,没有工作。在这里更改路径: String fileName = "/Users/dnelepov/Downloads/тест%20изображение.png"; String ts = new URI(null, null, fileName, null).getPath(); System.out.println("TS:" + ts); - Dmitry Nelepov
我不明白,你能否编辑答案并提供完整的代码:String fileName = "/Users/dnelepov/Downloads/тест%20изображение.png"; String ts = new URI(null, null, fileName, null).getPath(); System.out.println("TS:" + ts); - Dmitry Nelepov
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接