您的位置:首页 > 编程语言 > Java开发

Java随笔(2)I/O流中InputStream/OutputStream

2016-12-28 18:19 525 查看
如有转载,请注意:

http://blog.csdn.net/wjzj000/article/details/53911635

本菜开源的一个自己写的Demo,希望能给Androider们有所帮助,水平有限,见谅见谅…

https://github.com/zhiaixinyang/PersonalCollect (拆解GitHub上的优秀框架于一体,全部拆离不含任何额外的库导入)

https://github.com/zhiaixinyang/MyFirstApp(Retrofit+RxJava+MVP)

写在前面

操作File的次数多了,不免对流这个概念产生疑惑。时断时续的也找了不少的博客,但是看罢总觉着那个地方缺点什么。

所以今天自己就写篇博客记录自己学习的过程。

最近看到一篇写I/O的博客:

http://blog.csdn.net/smartbetter/article/details/51323904

这里借用他的一张图,增加增加门面…



引子

InuputStream类型:

根据《Java编程思想》的介绍,InputStream的作用是用来表示那些从不同数据源产生输入的类。这些数据源主要包含如下6大类:

1,字节数组。

2,String对象。

3,文件。

4,管道。

5,一个由其他种类的流组成的序列。

6,其他数据源,例网络获取…

每一种数据源都有对应的InputStream子类。



OutputStream类型:

该类别的类决定了输出的目标:字节数组,文件,管道。



Reader和Writer:

简单来说InputStream/OutputStream相关的类用在面向字节;而Reader/Write相关的类用在面向字符。

举个例子

缓冲输入文件:

打开一个文件用于字符输入,可以使用以String或File对象作为文件名的FileInputReader。为了提高速度,对文件进行缓冲,我们应将所产生的引用传给一个BufferedReader构造方法。BufferedReader也提供readLine()方法,所以这是我们最终的对象以及进行读取的接口。当readLine()返回null时,即可判断到达文件末尾。

/**
* BufferedReader的官方解释:
* 创建使用指定大小的输入缓冲区的缓冲!字符!输入流。
*/
BufferedReader br=new BufferedReader(new FileReader(fileName));
String s;
StringBuilder sb=new StringBuilder();
while ((s=br.readLine())!=null){
sb.append(s);
}
br.close();


自己简单测试一个读取本地File的demo

public static void main(String[] args)  {
try {
//关于FileReader,跳过代码就能看到解析
BufferedReader br=new BufferedReader(new FileReader(new File("E:\\test.txt")));
StringBuilder sb =new StringBuilder();
String lines;
while((lines=br.readLine())!=null){
//因为有中文,所以使用utf-8编码格式。
//但是new String的时候要把字符串转成字节
lines=new String(lines.getBytes(),"utf-8");
sb.append(lines);
}
System.out.println(sb.toString());
} catch (IOException e) {
e.printStackTrace();
}
}




关于FileReader

//我们可以看到内部使用的就是一个FileInputStream
public FileReader(File file) throws FileNotFoundException {
super(new FileInputStream(file));
}


那么这里我们可以很自然的想到一个问题,Reader和InputStream有什么样的区别?

咱们在最开始的时候提过,一个是操作字符,一个是操作字节。

《Java编程思想》中提到了如下的区别:

有时我们需要把来自“字节”层次结构中的类和“字符”层次结构中的类结合起来使用。为了实现这个目的,要用到“适配器”类:InputStreamReader可以把InputStream转化成Reader,而OutputStreamWeiter可以把OutputStream转换为Writer。

其次设计Reader和Writer继承层次结构主要是为了国际化。老的I/O流继承层次结构仅支持8位的字节流,并且不能很好地处理16位的Unicode字符。由于Unicode用于字符国际化(Java本身的char也是16位的Unicode),所以添加Reader和Writer继承层级结构就是为了在所有的I/O操作中都支持Unicode。

Unicode:就是ISO嫌各国各种编码方式太多,就本着自愿的原则整了这么一套编码方式。

“字节”是一个8位的物理存贮单元,而“字符”则是一个文化相关的符号。在unicode中,一个字符就是两个字节。一个汉字算两个英文字符的时代已经快过去了。无论是半角的英文字母,还是全角的汉字,它们都是统一的”一个字符“!

UTF-8就是每次8个位传输数据,而UTF-16就是每次16个位。UTF-8就是在互联网上使用最广的一种unicode的实现方式,这是为传输而设计的编码,并使编码无国界,这样就可以显示全世界上所有文化的字符了。

让我们通过其他方式来了解其中的不同:

//接下来我们来走一遍操作字节
try {
DataInputStream dis=new DataInputStream(new FileInputStream(new File("E:\\test.txt")));
int line;
byte[] b=new byte[1024];
//下边我们来瞅一瞅,这个传入byte[]的read()重载方法。
while((line=dis.read(b))!=-1){
//把字节转成字符
System.out.println(new String(b,"utf-8"));
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


//in就是我们在构造方法中传入的对应流对象
public final int read(byte b[]) throws IOException {
return in.read(b, 0, b.length);
}

public int read(byte b[], int off, int len) throws IOException {
//省略部分异常处理和判空的情况
int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte)c;

int i = 1;
try {
for (; i < len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
}




这里我们可以看到效果中的不同,操作字节的时候我们将回车也一并读取。而字符操作的时候我们是通过回车来进行判断并且通过StringBuilder进行拼接。

尾声

OK,关于流的用法就简单记录于此,以后有更吊的用法再回过来继续。

最后希望各位看官可以star我的GitHub,三叩九拜,满地打滚求star:

https://github.com/zhiaixinyang/PersonalCollect

https://github.com/zhiaixinyang/MyFirstApp
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java io