读写带有特殊字符的 .txt 文件

11

我打开Windows系统的记事本,然后写入:

Some lines with special characters
Special: Žđšćč

请点击 另存为... 并将文件名设置为 "someFile.txt",同时选择UTF-8编码。

在Java中我有以下代码:

FileInputStream fis = new FileInputStream(new File("someFile.txt"));
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
BufferedReader in = new BufferedReader(isr);

String line;
while((line = in.readLine()) != null) {                         
    printLine(line);
}
in.close();

但是我得到了问号和类似的“特殊”字符。为什么?

编辑:我有这个输入(一个在 .txt 文件中的一行)

665,Žđšćč

和这段代码

FileInputStream fis = new FileInputStream(new File(fileName));
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
BufferedReader in = new BufferedReader(isr);

String line;
while((line = in.readLine()) != null) {
    Toast.makeText(mContext, line, Toast.LENGTH_LONG).show();

    Pattern p = Pattern.compile(",");
    String[] article = p.split(line);

    Toast.makeText(mContext, article[0], Toast.LENGTH_LONG).show();
    Toast.makeText(mContext, Integer.parseInt(article[0]), Toast.LENGTH_LONG).show();
}
in.close();

对于那些不熟悉Android的人来说,Toast输出(Toast是一种在屏幕上显示特定文本的弹出方法)很好。控制台显示“奇怪的字符”(可能是因为控制台窗口的编码问题)。但解析整数时失败,因为控制台显示了这个(warning: toast output is just fine)- 问题

似乎该字符串包含一些无法显示/渲染的“奇怪”字符,但当我尝试解析它时,它会崩溃。有什么建议吗?

如果在记事本中使用ANSI,则可以正常工作(整数解析),并且没有像上面图片中那样的奇怪字符,但当然我的特殊字符无法正常工作。


1
printLine(line) 函数里面有什么内容? - Will
while((line = in.readLine()) != null) - Java真的允许这样做吗?我以为在Java中,赋值不被视为表达式... - Eric
@printLine只是将它打印到我的调试器(Eclipse)中-在这种情况下,第二行变成了“01-04 20:01:23.394:VERBOSE/line(32246):Special:ŽÄÅ¡ÄÄ” - svenkapudija
while((line = in.readLine()) != null) - 是的,Eric,你可以这样做。while循环正在评估的条件是(A != null),其中A是从输入流中读取一行的结果。 - xagyg
实际上我的问题有点不同,我的文件名是Žđšćč,我得到了一个错误:FileInputStream fis = new FileInputStream(new File("Žđšćč.txt")); 请帮忙。 - Bhanu Sharma
6个回答

17
这是输出控制台不支持那些字符。由于您正在使用Eclipse,您需要确保它配置为使用UTF-8。您可以通过 Window > Preferences > General > Workspace > Text File Encoding > 设置为UTF-8 来实现这一点。

另请参阅:


更新: 根据更新的问题和评论,显然是 UTF-8 BOM 惹的祸。记事本默认保存时添加UTF-8 BOM。看起来您的HTC上的JRE无法识别它。您可能要考虑在代码中使用此答案中概述的 UnicodeReader 示例,而不是InputStreamReader。它会自动检测并跳过BOM。

FileInputStream fis = new FileInputStream(new File(fileName));
UnicodeReader ur = new UnicodeReader(fis, "UTF-8");
BufferedReader in = new BufferedReader(ur);

与实际问题无关,但是在finally块中关闭资源是一个好习惯,以确保在发生异常的情况下它们将被关闭。

BufferedReader reader = null;
try {
    reader = new BufferedReader(new UnicodeReader(new FileInputStream(fileName), "UTF-8"));
    // ...
} finally {
    if (reader != null) try { reader.close(); } catch (IOException logOrIgnore) {}
}

另外无关的一点,我建议将Pattern p = Pattern.compile(",");放在循环外面,甚至将其作为静态常量,因为编译它相对较耗费时间,并且每次在循环内部执行都是不必要的。


这并不是因为我的SQLite INSERT也无法工作。如果我在我的HTC Desire上手动输入“žđšćč”并将其转发到INSERT语句 - 它可以正常工作。但是,如果我使用读取函数从我的.txt文件中读取相同的字符 - 就会崩溃。所以,这不仅仅是控制台输出。还有其他的问题吗? - svenkapudija
我刚刚更新了上面的代码... 我真的不知道到底发生了什么 =/ - svenkapudija
它现在在输出控制台上看起来正确吗?另一个原因可能是您的SQLite JDBC驱动程序和/或数据库没有将字符视为UTF-8。 - BalusC
这里有部分答案 - https://dev59.com/RFPTa4cB1Zd3GeqPgR6S。文档(.txt文件)是UTF-8格式,但为什么我的读取器没有将其作为UTF-8读取呢? - svenkapudija

2

你的代码看起来没问题 - 但是一个非常常见且容易犯的错误是将屏幕上打印的内容误认为是字符串中的内容。如果字符串没有被正确读取,请使用调试器进行检查。


1
记事本无法正确保存特殊符号。我曾遇到类似的问题,我使用了Notepad++代替记事本,并从中选择了UTF-8编码。这样做后,当我将字符串库方法应用于文本文件时,程序不再崩溃,而不像在记事本中创建文本文件时那样。

0

0

您是否在使用字符转换作为Servlet请求/响应的一部分? 如果是的话, request.setEncoding("UTF-8")
或者
response.setCharacterEncoding("UTF-8")

可以解决您的问题。


0

记事本可能无法处理非ASCII字符。请尝试其他文本编辑器。如果您想坚持使用Windows安装中提供的内容,请尝试使用WordPad。


他在记事本的“另存为”选项中选择了UTF-8。 - BalusC
如果我使用 Wordpad 并将其保存为“文本文档”,它会在第二行失败。如果我使用 Unicode 文本格式,它会在开头崩溃。 - svenkapudija

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