Java FileReader 编码问题
Posted
技术标签:
【中文标题】Java FileReader 编码问题【英文标题】:Java FileReader encoding issue 【发布时间】:2010-10-16 08:20:00 【问题描述】:我尝试使用 java.io.FileReader 读取一些文本文件并将它们转换为字符串,但我发现结果编码错误,根本不可读。
这是我的环境:
Windows 2003,操作系统编码:CP1252
Java 5.0
我的文件是 UTF-8 编码或 CP1252 编码的,其中一些(UTF-8 编码文件)可能包含中文(非拉丁)字符。
我使用以下代码来完成我的工作:
private static String readFileAsString(String filePath)
throws java.io.IOException
StringBuffer fileData = new StringBuffer(1000);
FileReader reader = new FileReader(filePath);
//System.out.println(reader.getEncoding());
BufferedReader reader = new BufferedReader(reader);
char[] buf = new char[1024];
int numRead=0;
while((numRead=reader.read(buf)) != -1)
String readData = String.valueOf(buf, 0, numRead);
fileData.append(readData);
buf = new char[1024];
reader.close();
return fileData.toString();
上面的代码不起作用。我发现 FileReader 的编码是 CP1252,即使文本是 UTF-8 编码的。但是 java.io.FileReader 的 JavaDoc 说:
这个类的构造函数假设 即默认字符编码 并且默认的字节缓冲区大小是 合适。
这是否意味着如果我使用 FileReader,我不需要自己设置字符编码?但是我目前确实得到了错误编码的数据,处理我的情况的正确方法是什么?谢谢。
【问题讨论】:
您还应该在循环中松开 String.valueOf() 并直接使用 StringBuffer.append(char[],int,int)。这样可以节省大量 char[] 的复制。还将 StringBuffer 替换为 StringBuilder。不过,这些都与您的问题无关。 我不想这么说,但是您在粘贴的部分之后阅读了 JavaDoc 吗?你知道,“要自己指定这些值,请在 FileInputStream 上构造一个 InputStreamReader。”的部分? 感谢您的评论,实际上我阅读了 JavaDoc,但我不确定是否应该自己指定这些值,并切换到“在 FileInputStream 上构造 InputStreamReader”。跨度> 是的,如果你知道文件不是平台默认编码,你必须告诉 InputStreamReader 使用哪一个。 【参考方案1】:是的,您需要指定要读取的文件的编码。
是的,这意味着您必须知道要读取的文件的编码。
不,没有通用方法猜测任何给定“纯文本”文件的编码。
The one-arguments constructors of FileReader
始终使用平台默认编码,这通常是个坏主意。
从 Java 11 开始,FileReader
也获得了接受编码的构造函数:new FileReader(file, charset)
和 new FileReader(fileName, charset)
。
在java早期版本中,需要使用new InputStreamReader(
new FileInputStream(pathToFile)
, <encoding>)
。
【讨论】:
InputStream is = new FileInputStream(filename);在这里我得到错误文件未找到错误与俄语文件名 +1 建议使用 InputStreamReader,但是在代码块中使用链接会导致难以复制和粘贴代码,如果可以更改,谢谢 在编码中是“UTF-8”还是“UTF8”。根据the Java SE reference on encoding,由于InputStreamReader
是java.io
类,它会是“UTF8”?
@NobleUplift:最安全的赌注是StandardCharsets.UTF_8
,那里不可能打错;-) 但是,如果你使用字符串"UTF8"
是正确的(尽管我似乎记得它将接受两种方式)。
@JoachimSauer 实际上,这是Byte Order Mark
的目的之一,以及.. 好吧.. 建立字节顺序! :) 因此,我发现 Java 的 FileReader 无法自动检测具有这种 BOM 的 UTF-16 很奇怪……事实上,我曾经写过一个 UnicodeFileReader
就是这样做的。不幸的是封闭源代码,但谷歌有它的UnicodeReader,非常相似。【参考方案2】:
FileReader
使用 Java 的平台默认编码,这取决于运行它的计算机的系统设置,并且通常是该区域用户中最流行的编码。
如果这个“最佳猜测”不正确,那么您必须明确指定编码。不幸的是,FileReader
不允许这样做(API 中的主要疏忽)。相反,您必须使用 new InputStreamReader(new FileInputStream(filePath), encoding)
并最好从有关文件的元数据中获取编码。
【讨论】:
“API 中的重大疏忽” - 感谢您的解释 - 我想知道为什么我找不到我想要的构造函数!干杯约翰 @Bhanu Sharma:这是一个不同级别的编码问题,请检查您从哪里获取文件名,以及是否硬编码编译器使用的编码。 @BhanuSharma:文件名编码问题与这个问题无关。查看许多现有的“为什么 Unicode 文件名在 Java 中不起作用”问题之一。剧透:像 FileReader 这样的 java.io API 使用 C 标准库文件系统调用,在 Windows 上不支持 Unicode;考虑改用 java.nio。 "FileReader
使用 Java 的平台默认编码,这取决于运行它的计算机的系统设置,并且通常是该地区用户中最流行的编码。"我不会这么说的。至少是 Windows。由于一些奇怪的技术/历史原因,JVM 忽略了 Unicode 是 Windows 上“所有新应用程序”的recommended 编码这一事实,而是 总是 就像旧编码配置为一样 旧版应用的回退是“平台默认设置”。
我什至会说,如果您的 Java 应用程序没有在每次读取或写入文件/流/资源时明确指定编码,它就是 坏了,因为它永远无法可靠地工作。【参考方案3】:
从 Java 11 开始,您可以使用它:
public FileReader(String fileName, Charset charset) throws IOException;
【讨论】:
【参考方案4】:对于 Java 7+ doc 你可以使用这个:
BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8);
这里是所有字符集doc
例如,如果您的文件在 CP1252 中,请使用 method
Charset.forName("windows-1252");
这里是 IO 和 NIO 的 Java 编码的其他规范名称doc
如果您不知道文件中的确切编码,您可以使用一些第三方库,例如来自 Google this 的这个工具,它工作得相当简洁。
【讨论】:
【参考方案5】:对于另一种拉丁语言,例如西里尔语,您可以使用如下内容:
FileReader fr = new FileReader("src/text.txt", StandardCharsets.UTF_8);
并确保您的.txt
文件以UTF-8
(但不是默认的ANSI
)格式保存。干杯!
【讨论】:
【参考方案6】:带 InputStreamReader 的 FileInputStream 比直接使用 FileReader 更好,因为后者不允许你指定编码字符集。
这里是一个使用 BufferedReader、FileInputStream 和 InputStreamReader 的例子,这样你就可以从文件中读取行。
List<String> words = new ArrayList<>();
List<String> meanings = new ArrayList<>();
public void readAll( ) throws IOException
String fileName = "College_Grade4.txt";
String charset = "UTF-8";
BufferedReader reader = new BufferedReader(
new InputStreamReader(
new FileInputStream(fileName), charset));
String line;
while ((line = reader.readLine()) != null)
line = line.trim();
if( line.length() == 0 ) continue;
int idx = line.indexOf("\t");
words.add( line.substring(0, idx ));
meanings.add( line.substring(idx+1));
reader.close();
【讨论】:
以上是关于Java FileReader 编码问题的主要内容,如果未能解决你的问题,请参考以下文章
使用 javascript 的 FileReader 获取/设置文件编码