Java读取UTF-8的txt文件第一行出现乱码“?”及解决
test.txt文件内容:
A中
2国
3
4
5
6
test.txt文件采用写字板保存为UTF-8格式
保存并关闭后使用写字板再次打开该UTF-8文档,中文、字母正常显示
测试代码:
- import java.io.BufferedReader;
-
import java.io.File;
-
import java.io.FileInputStream;
-
import java.io.InputStreamReader;
-
public class ReadTxtFile {
-
public static
void main(String[] args) {
-
try {
-
String charsetName = "UTF-8";
-
String path = "D:/to_delete/test.txt";
-
File file = new File(path);
-
if (file.isFile() && file.exists())
- {
-
InputStreamReader insReader = new InputStreamReader(
-
new FileInputStream(file), charsetName);
-
BufferedReader bufReader = new BufferedReader(insReader);
-
String line = new String();
-
while ((line = bufReader.readLine()) !=
null) {
- System.out.println(line);
- }
- bufReader.close();
- insReader.close();
- }
-
} catch (Exception e) {
-
System.out.println("读取文件内容操作出错");
- e.printStackTrace();
- }
- }
- }
程序执行结果:
?A中
2国
3
4
5
6
我的解决办法:
使用UltraEdit将上边的txt文件另存为UTF-8无BOM格式;
或者
使用Notepad++打开上边的txt文件执行如下操作“格式-->以UTF-8无BOM格式编码”,修改后将txt文本进行保存。
网上有篇非常好的文章,论述了问题出现的原因及解决办法
url:http://daimojingdeyu.javaeye.com/blog/397661
关键字: java 读utf-8, java写utf-8, 编码, utf-8 乱码
最近在处理文件时发现了同样类型的文件使用的编码可能是不同的。所以想将文件的格式统一一下(因为UTF-8的通用性,决定往UTF-8统一),遇见的第一个问题是:如何查看现有文件的编码方式。
上网找了一下,找到几篇比较好文章,这里就不转载啦把链接搞过来。
文件编码问题集锦
字符串编码(charset,encoding,decoding)问题原理
Java编码浅析
判定文件编码或文本流编码的方法
上面的几篇文章可以看成认识编码问题的“从入门到精通”
如果你看完了上面的文章,一定了解到了,在java中,class文件采用utf8的编码方式,JVM运行时采用utf16。Java的字符串是永远都是unicode的,采用的是UTF-16的编码方式。
想测试一下,java对UTF-8文件的读写的能力,结果发现了一个很郁闷的问题,如果通过java写的UTF-8文件,使用Java可以正确的读,但是如果用记事本将相同的内容使用UTF-8格式保存,则在使用程序读取是会从文件中多读出一个不可见字符。
测试代码如下:
-
-
import java.io.BufferedReader;
-
import java.io.File;
-
import java.io.FileInputStream;
-
import java.io.IOException;
-
import java.io.InputStreamReader;
-
-
-
public
class UTF8Test {
-
public
static
void main(String[] args)
throws IOException {
- File f = new File("./utf.txt");
- FileInputStream in = new FileInputStream(f);
- BufferedReader br = new BufferedReader(new InputStreamReader(in,
"UTF-8"));
-
- String line = br.readLine();
-
while(line !=
null)
- {
- System.out.println(line);
- line = br.readLine();
- }
- }
- }
- import java.io.BufferedReader;
-
import java.io.File;
-
import java.io.FileInputStream;
-
import java.io.IOException;
-
import java.io.InputStreamReader;
-
public class UTF8Test {
-
public static
void main(String[] args) throws IOException {
-
File f = new File("./utf.txt");
-
FileInputStream in = new FileInputStream(f);
-
-
BufferedReader br = new BufferedReader(new InputStreamReader(in,
"UTF-8"));
- String line = br.readLine();
-
while(line != null)
- {
- System.out.println(line);
- line = br.readLine();
- }
- }
- }
utf.txt通过记事本创建,另存时使用指定utf-8编码,其内容为:
引用
This is the first line.
This is second line.
正常的测试结果应该是直接输出utf.txt的文本内容。可是实际上却输出了下面的内容:
引用
?This is the first line.
This is second line.
第一行多出了一个问号。
通过上面的几篇文章应该可以想到是Java读取BOM(Byte Order Mark)的问题,在使用UTF-8时,可以在文件的开始使用3个字节的"EF BB BF"来标识文件使用了UTF-8的编码,当然也可以不用这个3个字节。
上面的问题应该就是因为对开头3个字节的读取导致的。开始不太相信这个是JDK的Bug,后来在多次试验后,问题依然存在,就又狗狗了一下,果然找到一个如下的Bug:
Bug ID:4508058
不过在我关掉的一些页面中记得有篇文件说这个bug只在jdk1.5及之前的版本才有,说是1.6已经解决了,从目前来看1.6只是解决了读取带有BOM文件失败的问题,还是不能区别处理有BOM和无BOM的UTF-8编码的文件,从Bug ID:4508058里的描述可以看出,这个问题将作为一个不会修改的问题关闭,对于BOM编码的识别将由应用程序自己来处理,原因可从另处一个bug处查看到,因为Unicode对于BOM的编码的规定可能发生变化。也就是说对于一个UTF-8的文件,应用程序需要知道这个文件有没有写BOM,然后自己决定处理BOM的方式。
在上面的while循环中可加入下面的代码,测试一下读出内容:
-
byte[] allbytes = line.getBytes("UTF-8");
-
for (int i=0; i < allbytes.length;
i++)
- {
-
int tmp = allbytes[i];
- String hexString = Integer.toHexString(tmp);
- hexString = hexString.substring(hexString.length() -2);
- System.out.print(hexString.toUpperCase());
- System.out.print(" ");
- }
- byte[] allbytes = line.getBytes("UTF-8");
-
for (int i=0; i < allbytes.length; i++)
- {
-
int tmp = allbytes[i];
- String hexString = Integer.toHexString(tmp);
-
-
hexString = hexString.substring(hexString.length() -2);
- System.out.print(hexString.toUpperCase());
-
System.out.print(" ");
- }
输出结果如下:
引用
EF BB BF 54 68 69 73 20 69 73 20 74 68 65 20 66 69 72 73 74 20 6C 69 6E 65 2E
?This is the first line.
54 68 69 73 20 69 73 20 73 65 63 6F 6E 64 20 6C 69 6E 65 2E
This is second line.
红色部分的"EF BB BF"刚好是UTF-8文件的BOM编码,可以看出Java在读文件时没能正确处理UTF-8文件的BOM编码,将前3个字节当作文本内容来处理了。
使用链接中提供的代码可以解决碰到的乱码问题:
http://koti.mbnet.fi/akini/java/unicodereader/
修改测试代码中的输入流后:
- BufferedReader br = new BufferedReader(new UnicodeReader(in, Charset.defaultCharset().name()));
- BufferedReader br = new BufferedReader(new UnicodeReader(in, Charset.defaultCharset().name()));
执行,可以看到正确的结果。
将用到的测试代码及UTF-8读取乱码解决(http://koti.mbnet.fi/akini/java/unicodereader)的源码放在了附件中
压缩包中的源代码
UnicodeInputStream.java
UnicodeReader.java
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
import java.io.*;
-
-
-
-
-
public class UnicodeReader
extends Reader {
- PushbackInputStream internalIn;
-
InputStreamReader internalIn2 = null;
- String defaultEnc;
-
private static
final int BOM_SIZE =
4;
-
-
-
-
-
-
-
- UnicodeReader(InputStream in, String defaultEnc) {
-
internalIn = new PushbackInputStream(in, BOM_SIZE);
-
this.defaultEnc = defaultEnc;
- }
-
public String getDefaultEncoding() {
-
return defaultEnc;
- }
-
-
-
-
-
public String getEncoding() {
-
if (internalIn2 ==
null)
-
return null;
-
return internalIn2.getEncoding();
- }
-
-
-
-
-
protected void init()
throws IOException {
-
if (internalIn2 !=
null)
-
return;
- String encoding;
-
byte bom[] =
new byte[BOM_SIZE];
-
int n, unread;
-
n = internalIn.read(bom, 0, bom.length);
-
if ((bom[0] == (byte)
0x00) && (bom[1] == (byte)
0x00)
-
&& (bom[2] == (byte)
0xFE) && (bom[3] == (byte)
0xFF)) {
-
encoding = "UTF-32BE";
-
unread = n - 4;
-
} else if ((bom[0] == (byte)
0xFF) && (bom[1] == (byte)
0xFE)
-
&& (bom[2] == (byte)
0x00) && (bom[3] == (byte)
0x00)) {
-
encoding = "UTF-32LE";
-
unread = n - 4;
-
} else if ((bom[0] == (byte)
0xEF) && (bom[1] == (byte)
0xBB)
-
&& (bom[2] == (byte)
0xBF)) {
-
encoding = "UTF-8";
-
unread = n - 3;
-
} else if ((bom[0] == (byte)
0xFE) && (bom[1] == (byte)
0xFF)) {
-
encoding = "UTF-16BE";
-
unread = n - 2;
-
} else if ((bom[0] == (byte)
0xFF) && (bom[1] == (byte)
0xFE)) {
-
encoding = "UTF-16LE";
-
unread = n - 2;
-
} else {
-
- encoding = defaultEnc;
- unread = n;
- }
-
-
if (unread > 0)
- internalIn.unread(bom, (n - unread), unread);
-
-
if (encoding == null) {
-
internalIn2 = new InputStreamReader(internalIn);
-
} else {
-
internalIn2 = new InputStreamReader(internalIn, encoding);
- }
- }
-
public void close()
throws IOException {
- init();
- internalIn2.close();
- }
-
public int read(char[] cbuf,
int off, int len)
throws IOException {
- init();
-
return internalIn2.read(cbuf, off, len);
- }
- }
UTF8Test.java
- import java.io.BufferedReader;
-
import java.io.File;
-
import java.io.FileInputStream;
-
import java.io.IOException;
-
import java.io.InputStreamReader;
-
import java.nio.charset.Charset;
-
public class UTF8Test {
-
public static
void main(String[] args) throws IOException {
-
File f = new File("./utf.txt");
-
FileInputStream in = new FileInputStream(f);
-
-
-
BufferedReader br = new BufferedReader(new UnicodeReader(in, Charset.defaultCharset().name()));
- String line = br.readLine();
-
while(line != null)
- {
- System.out.println(line);
- line = br.readLine();
- }
- }
- }
分享到:
相关推荐
Java解决UTF-8的BOM问题,使用“UnicodeInputStream”、“UnicodeReader”。
NULL 博文链接:https://baobeituping.iteye.com/blog/1280825
功能:1.解决PB创建UTF-8文件带BOM问题;...问度娘发现有相同问题,但解决方式是利用新建一个UTF-8的TXT文件后,再进行COPY加内容。感觉这样操作有点复杂。 后通过修改修改顺序,让BLOB提前编码UTF-8,解决了该问题。
VBA Fans读取和写入UTF-8格式文本文件
delphi保存读取utf-8的文本文件.mht
当需要将文本文件导入SAS中时,UTF-8编码的中文有可能会乱码,此文讨论了一种解决方法
PB的utf-8转换,包括加码解码等等 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
把含有本地编码的文件转成utf-8的,经常用于java文件的转码. 把编码gbk的java文件批量转成utf-8编码的文件.
读取ANSI 明码文件 读取Unicode 明码文件 读取Unicode big endian 明码文件 读取UTF-8 明码文件 读取UTF8 Bom 明码文件 读取UTF16-LE 明码文件 读取UTF16-BE 明码文件 到多字节字符串 扩展类CFilePlainCode
身份证读卡器生成的基本信息TEXT文件,由于是采用 GB 13000 的 UCS-2 编码格式,java读取出来是乱码,这个段代码就是解决转码问题的,亲测可用
选择文件夹,将指定文件里面的所有特定后缀的UTF-8编码文件转成GB2312文件,使用VS2013 ,MFC 开发.
易语言另类数据库读写UTF-8源码,另类数据库读写UTF-8
如何解决BOM:先放在服务器可执行目录下,使用 浏览器http://服务器ip/存放路径/bom.php来 访问,填写实际路径执行后可得到存在有BOM的PHP文件,然后再用notepad++打开,在菜单选“格式”->“转为UTF-8无BOM..”即可. ...
pb12 gb转utf-8
delphi 6-XE读取ANSI,unicode,unicode big,utf-8,utf-8BOM文件,保存utf8
基于labview2011开发的,使用操作系统自带的编码.net转换UTF8编码,实测从未出错,比LabVIEW自带...可用于中转,使得labview可以上传繁体数据到服务器,或解析服务器发送的繁体字数据,或读取UTF8编码的繁体字txt文档。
批量将任何编码格式的文件转换成UTF-8编码的文件,将工具放到需要转换的文件路径,双击运行,即可批量将路径下的所有文件(包含子文件夹中文件)转换成UTF-8编码的文件, 注意:不要在文件夹下放入无法读取的文件...
可以将TXT其他格式转为UTF-8格式,实现快捷的读取 ,可以实现批量转换,直接将文件选中添加进入,点击转换的格式即可。
Python 简单使用 pandas 读取excel 的 csv文件处理,支持utf-8和gbk编码自动识别。
C#:批量修改文本编码为UTF-8(含源码),可将指定文件夹下的所有是.txt、.cs、.lua后缀的文件(需要更多支持可自行修改)的编码格式修改为UTF-8,VS2013的项目。