使用 Java 重命名文件后,一些文件在 linux 系统上或通过 Java 无法访问

Posted

技术标签:

【中文标题】使用 Java 重命名文件后,一些文件在 linux 系统上或通过 Java 无法访问【英文标题】:After renaming files with Java some not accessible on linux system or via Java 【发布时间】:2020-08-22 16:08:22 【问题描述】:

我在使用 Java 的 linux 系统上读取(也可能是写入)文件时遇到问题。我的应用程序抱怨它无法读取某些音频文件,当我查看系统时,我注意到 ls -l 在这些文件上也失败了,并且所有问题文件都是包含带引号等字符的文件,例如 é,文件没有这些字符也没关系。

[root@N1-0247 Georges Bizet- Suites from Carmen & L'arlésienne]# pwd
/mnt/disk1/share/import/all/MusicUnmatched/WAV/Yan Pascal Tortelier/Georges Bizet- Suites from Carmen & L'arlésienne
[root@N1-0247 Georges Bizet- Suites from Carmen & L'arlésienne]# ls -l
ls: cannot access 20 - L' Arlésienne, suite for orchestra No. 1, from the incidental music- Farandole.WAV: No such file or directory
ls: cannot access 19 - L' Arlésienne, suite for orchestra No. 1, from the incidental music- Minuetto.WAV: No such file or directory
ls: cannot access 18 - L' Arlésienne, suite for orchestra No. 1, from the incidental music- Intermezzo.WAV: No such file or directory
ls: cannot access 17 - L' Arlésienne, suite for orchestra No. 1, from the incidental music- Pastorale.WAV: No such file or directory
ls: cannot access 16 - L' Arlésienne, suite for orchestra No. 1, from the incidental music- Carillon.WAV: No such file or directory
ls: cannot access 15 - L' Arlésienne, suite for orchestra No. 1, from the incidental music- Adagietto.WAV: No such file or directory
ls: cannot access 14 - L' Arlésienne, suite for orchestra No. 1, from the incidental music- Minuetto.WAV: No such file or directory
ls: cannot access 13 - L' Arlésienne, suite for orchestra No. 1, from the incidental music- Prélude.WAV: No such file or directory
ls: cannot access 08 - Carmen Suites for orchestra Nos. 1 & 2 (assembled by Ernest Guirard)- Chanson Du Toréador (Act II).WAV: No such file or directory
ls: cannot access 07 - Carmen Suites for orchestra Nos. 1 & 2 (assembled by Ernest Guirard)- Dans Bohème (Gypsy Song, Act II).WAV: No such file or directory
ls: cannot access 05 - Carmen Suites for orchestra Nos. 1 & 2 (assembled by Ernest Guirard)- Seguédille (Act I).WAV: No such file or directory
ls: cannot access 04 - Carmen Suites for orchestra Nos. 1 & 2 (assembled by Ernest Guirard)- Habeñera (Act I).WAV: No such file or directory
ls: cannot access 02 - Carmen Suites for orchestra Nos. 1 & 2 (assembled by Ernest Guirard)- Prélude (Prelude To Act I).WAV: No such file or directory
ls: cannot access 01 - Carmen Suites for orchestra Nos. 1 & 2 (assembled by Ernest Guirard)- Les Toréadors (Introduction To Act I).WAV: No such file or directory
total 192148
?????????? ? ?    ?           ?            ? 01 - Carmen Suites for orchestra Nos. 1 & 2 (assembled by Ernest Guirard)- Les Toréadors (Introduction To Act I).WAV
?????????? ? ?    ?           ?            ? 02 - Carmen Suites for orchestra Nos. 1 & 2 (assembled by Ernest Guirard)- Prélude (Prelude To Act I).WAV
-rw-rw-rw- 1 root root 36681194 Feb 21  2017 03 - Carmen Suites for orchestra Nos. 1 & 2 (assembled by Ernest Guirard)- La Grade Montante (Street Urchins' Chorus, Act I).WAV
?????????? ? ?    ?           ?            ? 04 - Carmen Suites for orchestra Nos. 1 & 2 (assembled by Ernest Guirard)- Habeñera (Act I).WAV
?????????? ? ?    ?           ?            ? 05 - Carmen Suites for orchestra Nos. 1 & 2 (assembled by Ernest Guirard)- Seguédille (Act I).WAV
-rw-rw-rw- 1 root root 16455464 Feb 21  2017 06 - Carmen Suites for orchestra Nos. 1 & 2 (assembled by Ernest Guirard)- Les Dragons D'Alcala (Entr'acte, Act II).WAV
?????????? ? ?    ?           ?            ? 07 - Carmen Suites for orchestra Nos. 1 & 2 (assembled by Ernest Guirard)- Dans Bohème (Gypsy Song, Act II).WAV
?????????? ? ?    ?           ?            ? 08 - Carmen Suites for orchestra Nos. 1 & 2 (assembled by Ernest Guirard)- Chanson Du Toréador (Act II).WAV
-rw-rw-rw- 1 root root 27743402 Feb 21  2017 09 - Carmen Suites for orchestra Nos. 1 & 2 (assembled by Ernest Guirard)- Intermezzo (Entr'acte, Act III).WAV
-rw-rw-rw- 1 root root 39886886 Feb 21  2017 10 - Carmen Suites for orchestra Nos. 1 & 2 (assembled by Ernest Guirard)- Marche Des Contrebandiers (Introduction To Act III).WAV
-rw-rw-rw- 1 root root 52822606 Feb 21  2017 11 - Carmen Suites for orchestra Nos. 1 & 2 (assembled by Ernest Guirard)- Nocturne (Micaela's Aria, Act III).WAV
-rw-rw-rw- 1 root root 23100378 Feb 21  2017 12 - Carmen Suites for orchestra Nos. 1 & 2 (assembled by Ernest Guirard)- Argonaise (Entr'acte, Act IV).WAV
?????????? ? ?    ?           ?            ? 13 - L' Arlésienne, suite for orchestra No. 1, from the incidental music- Prélude.WAV
?????????? ? ?    ?           ?            ? 14 - L' Arlésienne, suite for orchestra No. 1, from the incidental music- Minuetto.WAV
?????????? ? ?    ?           ?            ? 15 - L' Arlésienne, suite for orchestra No. 1, from the incidental music- Adagietto.WAV
?????????? ? ?    ?           ?            ? 16 - L' Arlésienne, suite for orchestra No. 1, from the incidental music- Carillon.WAV
?????????? ? ?    ?           ?            ? 17 - L' Arlésienne, suite for orchestra No. 1, from the incidental music- Pastorale.WAV
?????????? ? ?    ?           ?            ? 18 - L' Arlésienne, suite for orchestra No. 1, from the incidental music- Intermezzo.WAV
?????????? ? ?    ?           ?            ? 19 - L' Arlésienne, suite for orchestra No. 1, from the incidental music- Minuetto.WAV
?????????? ? ?    ?           ?            ? 20 - L' Arlésienne, suite for orchestra No. 1, from the incidental music- Farandole.WAV

我认为文件系统是 UTF8,至少如果我设置了

export LANG=en_US.UTF-8

在我的个人资料文件名中显示正确的名称。

早些时候,Java 应用程序将这些文件重命名为新名称,因此虽然报告了错误,但似乎是 Java 应用程序有问题,但我不知道是什么。

在我的 Java 启动脚本中有一行

export LC_ALL=en_US.UTF-8

我在其他 linux 系统或 Windows、MacOS 等上没有遇到过这个问题。

【问题讨论】:

使用什么文件系统来存储文件(ext4、FAT 等)? 你从哪里安装这个?以及哪个文件系统? 文件系统是xfs,它是linux机器上的本地文件系统,java应用程序直接运行在linux机器上。 可以添加代码库吗? 您能否通过运行以下语句列出文件来帮助复制,以便我们可以了解哪些(八进制)字节用于(其中一个)有问题的文件名? LC_ALL=C ls 这在我的系统上打印例如:'test1__'$'\303\251''__.txt' 而不是 test1__é__.txt 【参考方案1】:

尝试在你的 java start 命令中声明-Dfile.encoding=UTF-8

【讨论】:

【参考方案2】:

首先,两点:

1) 您收到ls 错误的事实表明问题是文件名和文件系统之间的问题,而不是Java 本身。无论您的程序是用什么语言编写的,或者实际上,如果您尝试直接在命令行上复制或重命名文件,您都会遇到同样的问题。

2) 问题不在于引号字符,正如引号字符出现在正确命名的文件中的事实所示 - 例如:

-rw-rw-rw- 1 root root 52822606 Feb 21  2017 11 - Carmen Suites for orchestra Nos. 1 & 2 (assembled by Ernest Guirard)- Nocturne (Micaela's Aria, Act III).WAV

所以,问题出在 unicode 字符 é 上。

这个字符是这个:https://www.compart.com/en/unicode/U+00E9,所以它由一个空字节和 E9 组成。

问题在于,像 xfs 这样的 POSIX 文件系统不允许文件名中有空字节(参见 What are all the illegal characters in the XFS filesystem?)

结果是,在那个文件系统中,你不能有那个字符的文件名。

因此,您必须更改文件名或文件系统。

例如,此页面列出了文件系统,指出那些允许在其文件名中包含 unicode 的文件系统:

https://en.wikipedia.org/wiki/Filename#Comparison_of_filename_limitations

(顺便说一句,该列表中有 Apple 的 HFS+,但有趣的是,它已被不允许文件名中包含 unicode 的 Apple 文件系统 APFS 取代 - https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/APFS_Guide/FAQ/FAQ.html

更改 Java 程序以修改文件名以将 é 替换为 e 的另一种方法:

    String safeFilename = filename.replaceAll("é", "e");

或者如果你喜欢:

    String safeFilename = filename.replaceAll( "\u00e9", "e" );

【讨论】:

嗨,这很有趣,但 U+00E9 是 UTF-16 值,但它不应该作为 UTF-8 值(即 0xC3 0xA9)写入文件吗? 此外,文件系统不会允许 Java 程序在路径名中包含空值。在那个级别,它(应该)是编码不可知的。 向您奖励诸如 xfs 之类的 POSIX 文件系统不允许空字节的信息。即使还没有解决问题,我将把它归结为文件系统损坏或文件复制到系统时出现问题。【参考方案3】:

这是一个很好的具有挑战性的难题,因为它很难调试

我尝试在带有 XFS 和 bash(作为 ls 内置)的 Debian 10 上使用 Java 11 重现 java.nio.Files,但无法重现名为 é 的文件的问题。

请尝试获得更简单的再现场景和更多细节,否则我只能猜测这可能与:

Unicode 规范化的兼容性问题,请参阅:https://docs.oracle.com/javase/tutorial/i18n/text/normalizerapi.html 还没有使用像这个问题中的 java.nio.Files 这样的现代 Java API java.io.File: accessing files with invalid filename encodings

问题还在于,这似乎很难调试,因为像 strace 这样的简单工具没有显示关于文件名字节的足够信息 getdents 系统调用来查看较低级别 API 发生了什么,请参阅:for what I mean

也许是时候采用不同的策略了?尝试只将歌曲的完整标题写到playlist file?总会有一些特殊字符在某些设置中会导致问题,如果你不小心的话,甚至是脚本中的空格、目录分隔符(斜杠或反斜杠)等(参见:this related question)

【讨论】:

确实我没有在所有地方使用文件,事实上我使用 ApacheCommons 重命名可能是问题吗? 还不确定,请回复我对要运行的问题的评论:LC_ALL=C ls 这样我们就可以更接近重现潜在问题 是的,我已经在同一台机器上进行了测试,该机器出现了一些新文件的问题,但我无法让它再次发生。所以我让我的应用程序采用可以由 ascii 处理的文件名,然后重命名它们,因此它们需要 UTF8 并且之后它们可以继续进行评估。但由于机器是黑盒设备,而我的应用程序是设备上唯一重命名文件的应用程序,我担心一定是我的应用程序导致了问题。 修复不可重现的问题太疯狂了,但在过去的一天里,我在阅读这篇文章时学到了很多关于 unicode 的知识,你不可能全部都赢 :-)【参考方案4】:

您的文件系统已损坏 - 这不是应用程序级别的问题,但根据将物理磁盘内容转换为文件名 + 数据的文件系统驱动程序,物理磁盘上的内容无效。您需要检查哪个设备代表您的文件系统(“mount”命令显示哪个设备安装到哪个目录 - 它可能类似于/dev/sda1。您需要将其重新安装为只读(这可能很棘手如果这是您的根文件系统)并运行 fsck /dev/sda1(或任何您的设备)来修复它。不能 100% 确定您可以恢复这些文件。

【讨论】:

以上是关于使用 Java 重命名文件后,一些文件在 linux 系统上或通过 Java 无法访问的主要内容,如果未能解决你的问题,请参考以下文章

文件夹重命名显示另一个程序正在打开

一个Java写的批量重命名文件小程序

提交后修复Mercurial存储库中的重命名

Gradle - 复制/重命名文件 - 为所有文件制作 0 文件大小/字节

关于 java 重命名文件夹的问题?

JAVA 使文件件里面的所有文件重命名新文件名(求源代码)