java中IO流之字节字符流的总结概述

概念

 
     这么庞大的体系里面,常用的就那么几个,我们把它们抽取出来,如下图:

 

 

Java语言定义了许多类专门负责各种方式的输入或者输出,这些类都被放在java.io包中。其中,

所有输入流类都是抽象类InputStream(字节输入流),或者抽象类Reader(字符输入流)的子类;

而所有输出流都是抽象类OutputStream(字节输出流)或者Writer(字符输出流)的子类。

【首先需要明白的是:流是干什么的???(为了永久性的保存数据)

  根据数据流向的不同分为输入流和输出流;

  根据处理数据类型的不同分为字符流和字节流;

【然后需要明白的是输入模式和输出模式是谁流向谁:

InputStream(字节输入流)和Reader(字符输入流)通俗的理解都是读(read)的。

OutputStream(字节输出流)和Writer(字符输出流)通俗的理解都是写(writer)的。

最后下面搞清楚各种流的类型的该怎么用,谁包含谁,理清思路。

字节流

字节流主要是操作byte类型数据,以byte数组为准,主要操作类就是OutputStream、InputStream

1:字节输入流
           字节输入流的抽象基类是InputStream,常用的子类是 FileInputStream和BufferedInputStream
           1)FileInputStream
           文件字节输入流:一切文件在系统中都是以字节的形式保存的,无论你是文档文件、视频文件、音频文件...,需要读取这些文件都可以用FileInputStream去读取其保存在存储介质(磁盘等)上的字节序列。
           FileInputStream在创建时通过把文件名作为构造参数连接到该文件的字节内容,建立起字节流传输通道。
           然后通过 read()、read(byte[])、read(byte[],int begin,int len) 三种方法从字节流中读取 一个字节、一组字节。
           
           2)BufferedInputStream
           带缓冲的字节输入流:上面我们知道文件字节输入流的读取时,是直接同字节流中读取的。由于字节流是与硬件(存储介质)进行的读取,所以速度较慢。而CPU需要使用数据时通过read()、read(byte[])读取数据时就要受到硬件IO的慢速度限制。我们又知道,CPU与内存发生的读写速度比硬件IO快10倍不止,所以优化读写的思路就有了:在内存中建立缓存区,先把存储介质中的字节读取到缓存区中。CPU需要数据时直接从缓冲区读就行了,缓冲区要足够大,在被读完后又触发fill()函数自动从存储介质的文件字节内容中读取字节存储到缓冲区数组。
           BufferedInputStream 内部有一个缓冲区,默认大小为8M,每次调用read方法的时候,它首先尝试从缓冲区里读取数据,若读取失败(缓冲区无可读数据),则选择从物理数据源 (譬如文件)读取新数据(这里会尝试尽可能读取多的字节)放入到缓冲区中,最后再将缓冲区中的内容返回给用户.由于从缓冲区里读取数据远比直接从存储介质读取速度快,所以BufferedInputStream的效率很高。

2.实例:

注意:read()方法读取的是一个字节,为什么返回是int,而不是byte。
字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,如果每次读取都返回byte,有可能在读到中间的时候遇到111111111;那么这11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,所以在读取的时候用int类型接收,如果11111111会在其前面补上;24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型

(1)FileInputStream的单个字节读取,FileOutputStream的单个字节写入:

//输出流
public class fos_demo {
    public static void main(String[] args) throws Exception {
        FileInputStream fis = new FileInputStream("a.txt");
        FileOutputStream fos = new FileOutputStream("b.txt", true);
        //FileOutputStream()后面加true指文件后面可追加

        int a = fis.read();//单个读取输入流字节
        System.out.println(a);
        int b = fis.read();
        System.out.println(b);
        int c = fis.read();
        System.out.println(c);
        fos.write(97);//单个读出字节
        fos.write(98);
        fos.write(99);
        fis.close();//关闭输出流
        fos.close();//关闭输出流
    }
}

 

(2)FileInputStream和FileOutputStream进行拷贝文本或者图片或者歌曲(以图片为例)

public class copy_demo1 {
    public static void main(String[] args) throws IOException{
        copy_2();
    }
    public static void copy_2() throws IOException{
        FileInputStream fis= new FileInputStream("aaa.jpg");
        FileOutputStream fos = new FileOutputStream("copy1.jpg");
        int b;
        while((b=fis.read())!=-1){
           fos.write(b);
        }
        fis.close();
        fos.close();
    }
}

(3)FileInputStream和FileOutputStream定义小数组进行操作:

//拷贝图片
package IO;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Array_copy {
    public static void main(String[] args) throws IOException {
        FileInputStream fis= new FileInputStream("aaa.jpg");
        FileOutputStream fos= new FileOutputStream("copy3.jpg");
        byte[] bytes = new byte[1024 * 8];//自定义字节大小
        int len;
        while ((len=fis.read(bytes))!=-1){
            fos.write(bytes,0,len);
        }
        fis.close();
        fos.close();
    }
}

 (4)关于buffer

package IO;

import java.io.*;

//Buffer 相当于缓冲池 输入输出的转化
public class Buffer_demo {
    public static void main(String[] args) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("ren.jpg"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.jpg"));
        int len;
        while((len=bis.read())!=-1){
            bos.write(len);
        }
        bis.close();
        bos.close();
    }
}
 
字符流
在程序中一个字符等于两个字节,那么java提供了Reader、Writer两个专门操作字符流的类。
 
实际中很多的数据是文本,又提出了字符流的概念,它是按虚拟机的encode来处理,也就是要进行字符集的转化。这两个之间通过 InputStreamReader,OutputStreamWriter来关联,实际上是通过byte[]和String来关联。 
 
 实例:
1.读写文件
//读文件
public class Demo_FileReader {
    public static void main(String[] args) throws Exception {
        FileReader reader = new FileReader("demo.txt");
        int len;
        while ((len=reader.read())!=-1){
            System.out.println((char) len);
        }
        reader.close();
}
//写文件
public class Demo_FileWriter {
    public static void main(String[] args) throws IOException {
        FileWriter fw = new FileWriter("pao.txt");
        fw.write("哈哈哈哈哈哈");;
        fw.write(97);
        fw.close();
    }
}

2.字符流是不可以拷贝非纯文本的文件(如图片)

因为在读的时候会将字节转换为字符,在转换过程中,可能找不到对应的字符,就会用?代替,写出的时候会将字符转换成字节写出去,如果是?,直接写出,这样写出之后的文件就乱了,看不了了。
public static void copy_2() throws IOException{
        BufferedReader br = new BufferedReader(new FileReader("aaa.jpg"));
        BufferedWriter bw = new BufferedWriter(new FileWriter("copy2.jpg"));
        int len;
        while ((len = br.read()) != -1) {
            bw.write(len);
        }
        br.close();
        bw.close();
    }

3.关于文本行(line)

//读取一个文本行
public class Buffered_demo {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("copy3.txt"));
        BufferedWriter bw = new BufferedWriter(new FileWriter("line.txt"));
        String line;
        while((line=br.readLine())!=null){
            bw.write(line);
        }
        br.close();
        bw.close();
    }
//使用默认输入缓冲区的大小创建新的行编号 reader。
public class Linenum_Demo {
    public static void main(String[] args) throws IOException {
        LineNumberReader lr = new LineNumberReader(new FileReader("copy3.txt"));
        String line;
        lr.setLineNumber(2);
        while((line=lr.readLine())!=null){
            System.out.println(lr.getLineNumber()+"  "+line);
        }

        lr.close();

    }

字节流与字符流的区别

字节流和字符流使用是非常相似的,那么除了操作代码的不同之外,还有哪些不同呢?

字节流在操作的时候本身是不会用到缓冲区(内存)的,是与文件本身直接操作的,而字符流在操作的时候是使用到缓冲区的

字节流在操作文件时,即使不关闭资源(close方法),文件也能输出,但是如果字符流不使用close方法的话,则不会输出任何内容,说明字符流用的是缓冲区,并且可以使用flush方法强制进行刷新缓冲区,这时才能在不close的情况下输出内容

 

那开发中究竟用字节流好还是用字符流好呢?

在所有的硬盘上保存文件或进行传输的时候都是以字节的方法进行的,包括图片也是按字节完成,而字符是只有在内存中才会形成的,所以使用字节的操作是最多的。

 

如果要java程序实现一个拷贝功能,应该选用字节流进行操作(可能拷贝的是图片),并且采用边读边写的方式(节省内存)。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 



 

 
     这么庞大的体系里面,常用的就那么几个,我们把它们抽取出来,如下图:

 

posted @ 2019-03-27 18:05  komorebi-rfj  阅读(275)  评论(0编辑  收藏  举报