您的位置:首页 > 其它

io读文件显示在控制台问题汇总

2016-07-15 22:38 363 查看
今天回顾并手写了一个读文件并显示在控制台上的代码,如下:

import java.io.*;

public class ioTest {

public static void main(String[] args){
String path = "G:/javaworkspace/Test/io/src/";
File file = new File(path + "test.txt");
InputStream inputStream = null;
int i=0;
try {
inputStream = new FileInputStream(file);
byte[] bytes = new byte[16];
while ((i = inputStream.read(bytes))!=-1){
String str = new String(bytes);
System.out.print(str);
}
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}


test.txt文件原内容如下(随机内容,以UTF-8保存):



一,首先想到比较一下read()和read(byte[] b)的区别

根据api帮助文档加上些许个人理解,

read()从输入流中读取数据的下一个字节,返回0到255范围内的int字节值。如果因为已经到达流末尾而没有可用的字节,则返回-1。在输入数据可用、检测到流末尾或者抛出异常前,此方法一直阻塞。

read(byte[] b)从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。以整数形式返回实际读取的字节数。在输入数据可用、检测到文件末尾或者抛出异常前,此方法一直阻塞。如果 b 的长度为 0,则不读取任何字节并返回 0;否则,尝试读取至少一个字节。如果因为流位于文件末尾而没有可用的字节,则返回值 -1;否则,至少读取一个字节并将其存储在 b 中。将读取的第一个字节存储在元素 b[0] 中,下一个存储在 b[1] 中,依次类推。读取的字节数最多等于 b 的长度。

读取文档如果用read()来写的话,需要每个字节强转为相应char类型,但是读取出来的汉字肯定就是乱码了,因为char只能一个字节一个字节读,读取英文还是可以的。

二,问题1,出现全部乱码

1.上面代码运行结果如图:



这是因为在java中,class文件采用utf8的编码方式,JVM运行时采用utf16。Java的字符串是永远都是unicode的,采用的是UTF-16的编码方式,我理解,也就是所谓的解错码

要解决这一问题需要使用外部资源采用的字符集来读取外部数据,改进代码如下:

import java.io.*;

public class ioTest2 {
public static void main(String[] args) {
String path = "G:/javaworkspace/Test/io/src/";
File file = new File(path + "test.txt");
InputStream in = null;
String line;
StringBuffer sb = new StringBuffer();
try {
in = new FileInputStream(file);

Reader reader = new InputStreamReader(in, "UTF-8");
//创建使用指定字符集的 InputStreamReader
//增加缓冲功能,提高效率
BufferedReader br = new BufferedReader(reader);
while ((line = br.readLine()) != null) {
sb.append(line);
}
if (br != null) {
br.close();
}
String content = sb.toString();
System.out.print(content);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

}


主要起作用的是Reader reader = new InputStreamReader(inputStream, “UTF-8”);

这一句使用外部资源的字符集也就是UTF-8来进行读文件,从而能够以正确方式转化。

三,问题2,控制台输出出现首字符问号的问题

上面代码运行结果如下:



对于这一点我十分疑惑,花费了很长时间在网上查找资料,最终这篇博客对我帮助很大,而且这篇博客写的非常充实、资料也很丰富,对于解决乱码问题有很好的帮助:

解决乱码问题的博客

从这篇博客得知,这是因为文本BOM(Byte Order Mark)的机制,带有BOM的UTF-8文本首三个字节为EF BB BF ,而JDK一直存在一个BUG,那就是无法识别前三个字节把他们也当作文本内容读取了,该BUG为:

Bug ID:4508058

可以从描述看出,这个问题将作为一个不会修改的问题关闭,对于BOM编码的识别将由应用程序自己来处理,原因可从另处一个bug处查看到,因为Unicode对于BOM的编码的规定可能发生变化。也就是说对于一个UTF-8的文件,应用程序需要知道这个文件有没有写BOM,然后自己决定处理BOM的方式。

我将test.txt文件用Editplus打开,用十六进制查看器看到:



首三个字节的确是EF BB BF。

我将test.txt文件用去掉BOM的UTF-8保存,并用十六进制查看器看到:



的确是去掉了首三个字节。

运行结果如下:



经过千辛万苦,终于去掉了所有乱码,但是我这只是修改了我文件的保存方式,这篇博客中也提到了对于带BOM的文件解决办法:

http://koti.mbnet.fi/akini/java/unicodereader/

在这里我也附上里面所提到的解决乱码问题非常好的几篇文章,亲测的确很有帮助:

文件编码问题集锦

字符串编码(charset,encoding,decoding)问题原理

Java编码浅析

判定文件编码或文本流编码的方法

四,问题3,回车换行没有读出来

细心的小伙伴们都发现了,控制台上显示出来的跟文件相比,回车换行并没有读出来,这个问题我也找到了解决办法,通过 commons-io-*.jar 。

代码如下:

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;

import org.apache.commons.io.FileUtils;

public class commonsIOTest{
public static void main(String[] args) {
String path = "G:/javaworkspace/Test/io/src/";
File file = new File(path + "test.txt");
try {
//方法1
String content = FileUtils.readFileToString(file,"UTF-8");
System.out.println(content);

//方法2
List<String> contents = FileUtils.readLines(file,"UTF-8");
for (String string : contents) {
System.out.println(string);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}

}

}


运行结果:



Apache 的io工具包非常简便,好用,可以直接解决换行没读的问题,但是我测试了一下,首字符为问号的问题依然没有解决。

Apache的io工具包使用简例
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息