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

如有转载,请注意:
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
这里借用他的一张图,增加增加门面…

Java随笔(2)I/O流中InputStream/OutputStream_第1张图片

引子

InuputStream类型:

  • 根据《Java编程思想》的介绍,InputStream的作用是用来表示那些从不同数据源产生输入的类。这些数据源主要包含如下6大类:
    • 1,字节数组。
    • 2,String对象。
    • 3,文件。
    • 4,管道。
    • 5,一个由其他种类的流组成的序列。
    • 6,其他数据源,例网络获取…
  • 每一种数据源都有对应的InputStream子类。

Java随笔(2)I/O流中InputStream/OutputStream_第2张图片


OutputStream类型:

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

Java随笔(2)I/O流中InputStream/OutputStream_第3张图片


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();
        }
    }

Java随笔(2)I/O流中InputStream/OutputStream_第4张图片

  • 关于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;
    }

Java随笔(2)I/O流中InputStream/OutputStream_第5张图片

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


尾声

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

最后希望各位看官可以star我的GitHub,三叩九拜,满地打滚求star:
https://github.com/zhiaixinyang/PersonalCollect
https://github.com/zhiaixinyang/MyFirstApp

你可能感兴趣的:(java,杂谈系列,java,io)