Java 是否将文件名获取为UTF-8?(ä;、ü;、ö;…始终是';?';)

Java 是否将文件名获取为UTF-8?(ä;、ü;、ö;…始终是';?';),java,encoding,utf-8,Java,Encoding,Utf 8,我必须读取一些文件的名称,并将它们作为字符串放入列表中。这并不难,我只是对一些角色有一些问题,比如ä,ö,ü。。。它们在我的字符串中总是作为一个“?” 有什么问题吗?那么编码呢。好的,这应该很容易。。。我就是这么想的。所以我尝试使用如下函数: 新字符串(插入.getBytes(“UTF-8”) 或 新字符串(插入.getBytes(“ISO-8859-1”),“UTF-8”) 因为大多数文件都是ISO-8859-1 这没有帮助。这是我的代码: ... File[] fileList = dir.

我必须读取一些文件的名称,并将它们作为字符串放入列表中。这并不难,我只是对一些角色有一些问题,比如ä,ö,ü。。。它们在我的字符串中总是作为一个“?”

有什么问题吗?那么编码呢。好的,这应该很容易。。。我就是这么想的。所以我尝试使用如下函数:

新字符串(插入.getBytes(“UTF-8”)
新字符串(插入.getBytes(“ISO-8859-1”),“UTF-8”)
因为大多数文件都是ISO-8859-1

这没有帮助。这是我的代码:

...
File[] fileList = dir.listFiles();
String insert;
for(File f : fileList) {
...
insert=f.getName().substring(0,f.getName().length()-4);
                insert=insert.charAt(0)+insert.substring(1,insert.length()).toLowerCase().replaceFirst("([0-9]*(_s?(i)?(_dat)?)*$)", "").replaceFirst("_", " ");
...
System.out.println("test UTF8: " + new String(insert.getBytes("UTF-8"))); //not helping
System.out.println("test ISO , UTF8: " + new String(insert.getBytes("ISO-8859-1"), "UTF-8")); //not helping
...
names.add(insert);
}
在我的列表的末尾有很多带有“?”字符的字符串。 如何解决这个问题?如果不是只有ISO-8859-1文件,那么最好的方法是什么?(假设有很多未知的编码文件)


谢谢!

文件名内容的编码与文件名本身的编码无关

您应该从
System.out.println(insert)

如果没有,则意味着shell具有与系统默认字符编码不同的字符编码(这种情况很少发生;这通常是shell中切换编码的显式命令的结果)

如果在shell中列出目录时正确显示了文件名,我希望它们能够正确显示,而无需在Java程序中指定编码


如果shell无法显示字符(它将替换替换字符0xFFFD(�) 对于这些不可打印的字符),Java应用程序无法对此进行任何更改。您需要更改终端字符编码、安装正确的字体等;这是操作系统问题,而不是Java问题

同时,即使您的终端无法显示正确的结果,Java程序也应该在没有您干预的情况下正确处理字符编码


文件
API后面的库正在为您的系统找出正确的字符编码,并执行必要的字符解码。同样,数据库驱动程序应与数据库协商以确定正确的编码,并代表您的应用程序执行任何必要的字节编码。

字符串中的问号、空格等表示在从一个字符集转换到另一个字符集时,某个地方无法识别特定字符

在您的案例中,问题可能发生在几个地方:

  • 当Java程序从目录(在
    dir.listFiles()
    调用中)读取文件名时,可能会发生这种情况

  • 当您将字符打印到控制台流时,可能会发生这种情况

在这两种情况下,根本原因很可能是Java认为区域设置应该是什么与操作系统和/或命令shell使用的设置不匹配

作为一个实验,试着从命令行中列出一个包含有问题文件名的目录。你看到问号或其他splat了吗


要执行的第二个实验是修改Java程序,将其中一个问题字符串转储为表示每个字符的字符代码的数字序列。是否在您编写的注释中看到ASCII/Unicode
“?”


@mdrg:嗯,有一个问题。我必须读取文件名,然后将它们放入数据库。而且有很多“?”,这不应该是…-Lissy 27分钟前

我的猜测是,要插入文件名的列指定US-ASCII作为编码,并用替换字符替换该范围之外的字符,在您的情况下,替换字符是问号


因此,您必须找出数据库表中存储文件名的列的编码。各种产品都有各种用于检索该信息的语法。

鉴于问题下前后的扩展注释,现在看来这要么是字体问题,要么(可能更可能)文件名编码问题

touch filenäme
ls filen*me
我要求Lissy运行以下命令,让我们找出问题所在。如果她确定文件名中包含“ä”,但当她
ls
文件名时,该字符未出现,则此命令将告诉我们这是字体还是编码问题

touch filenäme
ls filen*me
如果显示“filenäme”在
ls
的输出中,我们知道问题出在创建/复制文件到这个系统上。如果创建文件的程序没有意识到文件系统编码是什么,或者太愚蠢而没有做正确的事情,这可能会发生。
convmv
程序可能是解决这个问题的最佳方法

convmv -f ENCODING -t utf8 -r .
问题是什么是正确的编码。可能包括UTF-16、cp850或iso8859-1。
convmv--list
将向您显示(您的系统)当前已知的由于上面列出的命令只显示了它可以做什么,所以可以使用不同的编码运行多次,直到找到一个适用于所有文件的编码


如果这是一个字体问题,我们必须研究一下,在Java 1.6中,您可以使用System.console()而不是System.out.println()来向控制台显示重音字符

public class Test {
  public static void main(String args[]){
   String s = "caractères français :  à é \u00e9"; // Unicode for "é"
   System.console().writer().println(s);
  }
}
输出是

C:\temp>java Test
caractères français :  à é é

您是从磁盘还是从其他文件读取文件名?有一种首选的OS文件名编码,但如果您是从未知编码的文件获取文件名,则可能会遇到麻烦。如果您可以读取具有特定编码(正确编码)的文件然后将它们写回磁盘,您就不会得到奇怪的字符,那么您的编码处理就可以了。在这种情况下,只是您的控制台没有用于显示的字符。@mdrg:嗯,有一个问题