Java 从字符串创建路径时出错,linux 是否将文件名限制为 8 位字符集

Java error creating Path from String, does linux limit filenames to 8bit charset

我的 Java 代码在 Unix 系统上将字符串转换为实际路径时出现问题

contains unmappable characters: /out/K/Kyuss/?And the Circus Leaves Town/09 - Size Queen.mp3
java.nio.file.InvalidPathException: Malformed input or input contains unmappable characters: /out/K/Kyuss/?And the Circus Leaves Town/09 - Size Queen.mp3
    at sun.nio.fs.UnixPath.encode(UnixPath.java:147)
    at sun.nio.fs.UnixPath.<init>(UnixPath.java:71)
    at sun.nio.fs.UnixFileSystem.getPath(UnixFileSystem.java:281)
    at java.io.File.toPath(File.java:2234)
    at com.jthink.songkong.analyse.analyser.SongSaver.saveRenamedFile(SongSaver.java:891)
    at com.jthink.songkong.analyse.analyser.SongSaver.realSave(SongSaver.java:809)
    at com.jthink.songkong.analyse.analyser.SongSaver.saveSongToFile(SongSaver.java:630)
    at com.jthink.songkong.analyse.analyser.SongSaver.saveChanges(SongSaver.java:190)
    at com.jthink.songkong.analyse.analyser.SongSaver.call(SongSaver.java:165)
    at com.jthink.songkong.analyse.analyser.SongSaver.call(SongSaver.java:59)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

问题字符是椭圆字符“...”(在错误消息输出中显示为?),它不是 8 位字符,但为什么需要它我不知道 unix 上有这样的限制系统。

Linux 将文件名视为字节串。是应用程序选择以他们想要的方式解释字节串。 More info here. 通常程序将文件名解释为 UTF-8,但这取决于许多因素,包括 LANG 环境变量。

问题是 Java 使用 LANG 变量来猜测您的文件名使用的编码。如果您没有正确设置它(例如 en_US.UTF-8),它可能会假定您的文件名是 ASCII,并且它拒绝对椭圆字符进行编码,因为它没有 ASCII 编码。

重现它的小例子:

import java.io.File;

public class Test {
    public static void main(String[] args) {
        File f = new File("\u2026");
        f.toPath();
    }
}

如果你 运行 它与 LANG=C 你会得到错误。

$ LANG=C java Test
Exception in thread "main" java.nio.file.InvalidPathException: Malformed input or input contains unmappable characters: ?
    at sun.nio.fs.UnixPath.encode(UnixPath.java:147)
    at sun.nio.fs.UnixPath.<init>(UnixPath.java:71)
    at sun.nio.fs.UnixFileSystem.getPath(UnixFileSystem.java:281)
    at java.io.File.toPath(File.java:2234)
    at Test.main(Test.java:6)

如果你 运行 它与 LANG=en_US.UTF-8 它工作正常。

$ LANG=en_US.UTF-8 java Test
# No crash!

如果你 运行 它没有设置 LANG 它会选择你的系统配置的任何东西,如果它不支持 unicode 就会抛出。

不幸的是,我看不到从您的程序中修复此行为的简单方法。 UnixPath.encode 使用 Charset.defaultCharset()there's no way to change it at runtime。您必须确保 LANG 配置正确。