Java IO流总结归纳,输入输出流

Java IO流总结归纳,输入输出流

IO体系

字符流&字节流 区别

  • 读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。

  • 处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。

  • 字节流:一次读入或读出是8位二进制。使用字节流时,即使流没有关闭,最终也可以输出到文件;

  • 字符流:一次读入或读出是16位二进制。使用字符流时,所有的内容保存在缓冲区,流关闭时 会强制性的将缓冲区内容写到文件中,如果没有关闭流,文件中就不会有内容输出。

字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。

设备上的数据无论是图片或者视频,文字,它们都以二进制存储的。二进制的最终都是以一个8位为数据单元进行体现,所以计算机中的最小数据单元就是字节。意味着,字节流可以处理设备上的所有数据,所以字节流一样可以处理字符数据。

结论:只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。

InputStream

常用方法描述
public abstract int read( )读取一个byte的数据,返回值是高位补0的int类型值
若返回值=-1说明没有读取到任何字节读取工作结束
public int read(byte b[ ])读取数据放到b数组中。返回值是读取的字节数。
public int read(byte b[ ], int off, int len)从输入流中最多读取len个字节的数据,存放到偏移量为off的b数组中
public int available( )返回输入流中可以读取的字节数。
public int close( )使用完后,必须对我们打开的流进行关闭

主要子类

  • FileInputStream:把一个文件作为InputStream,实现对文件的读取操作

  • ByteArrayInputStream:把内存中的一个缓冲区作为InputStream使用

  • StringBufferInputStream:把一个String对象作为InputStream

  • PipedInputStream:实现了pipe的概念,主要在线程中使用

  • SequenceInputStream:把多个InputStream合并为一个InputStream

OutputStream

常用方法描述
public void write(byte b[ ])将参数b中的字节写到输出流
public void write(byte b[ ], int off, int len)将参数b的从偏移量off开始的len个字节写到输出流
public abstract void write(int b)先将int转换为byte类型,把低字节写入到输出流中
public void flush( )将数据缓冲区中数据全部输出,并清空缓冲区
public void close( )关闭输出流并释放与流相关的系统资源

主要子类

  • ByteArrayOutputStream:把信息存入内存中的一个缓冲区中

  • FileOutputStream:把信息存入文件中

  • PipedOutputStream:实现了pipe的概念,主要在线程中使用

  • SequenceOutputStream:把多个OutStream合并为一个OutStream

注:流结束的判断:方法read()的返回值为-1时;readLine()的返回值为null时。

文件输入流 FileInputStream

import java.io.FileInputStream;
import java.io.IOException;

public class A1 {
    public static void main(String[] args) throws IOException {
        String filePath = "a.txt";
        FileInputStream fis = new FileInputStream(filePath);
        int a;
        String result = "";
        // 流结束的判断:方法read()的返回值为-1时;readLine()的返回值为null时。
        while ((a = fis.read()) != -1) {
            result += a;
        }
        System.out.println(result);
        /*返回值是 int 类型的,会将取出来的一个字节高位会补 0 成一个 int 型。所以输出来的应该这个数据的 ASCII 码。*/
    }
}

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LqJqZ72j-1620811920712)(C:\Users\Heaven\AppData\Roaming\Typora\typora-user-images\image-20210512154502603.png)]

分析:

1.我们看到输入哈,输出?,但这并不是我们想要的。为什么会这样呢?我们来看一下 ? 的 ASCII 码,刚好是 229,这我们就知道它只取了第一字节ASCII码对应的字符。

2.会输出一些整数即 ASCII 码,因为读的时候是一个字节一个字节的读,而中文又不止一个字节,到底要几个字节来表示,这要取决于编码集(我这里的是拆成了三个字节,两个字节是用来标记一行的)。反正会拆成几个字节来读。

文件输出流 FileoutStream

用法描述
FileOutputStream(File file/ String filepath)创建一个向指定 File或String 对象表示的文件中写入数据的文件输出流。
FileOutputStream(File file, boolean append)append表示内容是否追加

注:

(1)文件中写数据时,若文件已经存在,则覆盖存在的文件;

(2)读/写操作结束时,应调用close方法关闭流。

import java.io.FileOutputStream;
import java.io.IOException;

public class A1 {
    public static void main(String[] args) throws IOException {
        String filePath = "a.txt";
        FileOutputStream fos = new FileOutputStream(filePath);
        int a;
        while ((a = System.in.read()) != -1) {
            fos.write(a);
        }
    }
}

缓冲流 BufferedInputStream/ BufferedOutputStream(也称包装流)

首先抛出一个问题,有了InputStream为什么还要有BufferedInputStream?

BufferedInputStreamBufferedOutputStream这两个类分别是FilterInputStreamFilterOutputStream的子类,作为装饰器子类,使用它们可以防止每次读取/发送数据时进行实际的写操作,代表着使用缓冲区。

我们有必要知道不带缓冲的操作,每读一个字节就要写入一个字节,由于涉及磁盘的IO操作相比内存的操作要慢很多,所以不带缓冲的流效率很低。带缓冲的流,可以一次读很多字节,但不向磁盘中写入,只是先放到内存里。等凑够了缓冲区大小的时候一次性写入磁盘,这种方式可以减少磁盘操作次数,速度就会提高很多!

同时正因为它们实现了缓冲功能,所以要注意在使用BufferedOutputStream写完数据后,要调用flush()方法或close()方法,强行将缓冲区中的数据写出。否则可能无法写出数据。与之相似还BufferedReaderBufferedWriter两个类。

现在就可以回答在本文的开头提出的问题:

BufferedInputStreamBufferedOutputStream类就是实现了缓冲功能的输入流/输出流。使用带缓冲的输入输出流,效率更高,速度更快。

总结:
  • BufferedInputStream 是缓冲输入流。它继承于FilterInputStream
  • BufferedInputStream 的作用是为另一个输入流添加一些功能,例如提供“缓冲功能”以及支持mark()标记和reset()重置方法。
  • BufferedInputStream 本质上是通过一个内部缓冲区数组实现的。例如,在新建某输入流对应的BufferedInputStream后,当我们通过read()读取输入流的数据时,BufferedInputStream会将该输入流的数据分批的填入到缓冲区中。每当缓冲区中的数据被读完之后,输入流会再次填充数据缓冲区;如此反复,直到我们读完输入流数据位置。
使用
BufferedInputStream(InputStream in, int size)使用指定buf大小、底层字节输入流构建bis
BufferedOutputStream(OutputStream out, int size);使用指定大小、底层字节输出流构造bos
注意:

我们需要手动的去刷新缓冲区。调用包装流的 flush() 方法。这个方法的作用就是将缓存区的内容写入到硬盘上并清空缓存区。

当然能不能不写 flush()方法也让它刷新呢?

答:可以,调用 close() 方法关闭流即可。当你调用 close()方法时它会先刷新缓存区。这就是刚才上面所说要记得用完之后要关闭流。不过最好有使用到包装流的时候两个方法都记得写上。

void write(char ch);//写入单个字符。
 
void write(char []cbuf,int off,int len)//写入字符数据的某一部分。
void write(String s,int off,int len)//写入字符串的某一部分。
 
void newLine()//写入一个行分隔符。
 
void flush();//刷新该流中的缓冲。将缓冲数据写到目的文件中去。
 
void close();//关闭此流,再关闭前会先刷新他。
Eg.复制文件
import java.io.*;
public class A1 {
    public static void main(String[] args) throws IOException {
        String oldFile = "1.JPEG";
        String newFile = "2.JPG";
        InputStream inputStream = new FileInputStream( oldFile ) ;
        BufferedInputStream bufferedInputStream = new BufferedInputStream( inputStream ) ;

        OutputStream outputStream = new FileOutputStream( newFile ) ;
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream( outputStream ) ;

        byte[] b=new byte[1024];   //代表一次最多读取1KB的内容

        int length = 0 ; //代表实际读取的字节数
        while( (length = bufferedInputStream.read( b ) )!= -1 ){
            //length 代表实际读取的字节数
            bufferedOutputStream.write(b, 0, length );
        }
        //缓冲区的内容写入到文件
        bufferedOutputStream.flush();
    }
}

缓冲流 BufferedReader/BufferedWriter

构造函数
BufferedReader(Reader in, int sz)创建一个使用指定大小输入缓冲区的缓冲字符输入流。
BufferedWriter(Writer out, int sz)创建一个使用给定大小输出缓冲区的新缓冲字符输出流。

方法:

int  read()  //读取单个字符。
int  read(char[] cbuf, int off, int len)  //将字符读入数组的某一部分。
String  readLine()  //读取一个文本行。
boolean	 ready()  //判断此流是否已准备好被读取。
void  reset()  //将流重置到最新的标记。
long  skip(long n)  //跳过字符。
void  close() //关闭该流并释放与之关联的所有资源。
void  mark(int readAheadLimit) //标记流中的当前位置。
boolean  markSupported() //判断此流是否支持 mark() 操作(它一定支持)。
    
void  close()  // 关闭此流,但要先刷新它。
void  flush()  //刷新该流的缓冲。
void  newLine() //写入一个行分隔符。
void  write(char[] cbuf, int off, int len) //写入字符数组的某一部分。
void  write(int c) //写入单个字符。
void  write(String s, int off, int len) //写入字符串的某一部分。
Eg.键入存文件
import java.io.*;
public class A1 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new FileWriter(new File("a.txt")));
        String s;
        while ((s = br.readLine()).length() > 0) {
            bw.write(s, 0, s.length());
            bw.flush();
        }
        bw.close();
    }
}

转换流 InputStreamReader/OutputStreamWriter

InputStreamReader 是字符流Reader的子类,是字节流通向字符流的桥梁。你可以在构造器重指定编码的方式,如果不指定的话将采用底层操作系统的默认编码方式,例如 GBK 等。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。一次只读一个字符。

InputStreamReader(Inputstream  in) //创建一个使用默认字符集的 InputStreamReader。

InputStreamReader(Inputstream  in,Charset cs) //创建使用给定字符集的 InputStreamReader。

InputStreamReader(InputStream in, CharsetDecoder dec) //创建使用给定字符集解码器的 InputStreamReader。

InputStreamReader(InputStream in, String charsetName)  //创建使用指定字符集的 InputStreamReader。

OutputStreamWriter 是字符流Writer的子类,是字符流通向字节流的桥梁。每次调用 write()方法都会导致在给定字符(或字符集)上调用编码转换器。在写入底层输出流之前,得到的这些字节将在缓冲区中累积。一次只写一个字符。

OutputStreamWriter(OutputStream out) //创建使用默认字符编码的 OutputStreamWriter

OutputStreamWriter(OutputStream out, String charsetName) //创建使用指定字符集的 OutputStreamWriter。

OutputStreamWriter(OutputStream out, Charset cs) //创建使用给定字符集的 OutputStreamWriter。

OutputStreamWriter(OutputStream out, CharsetEncoder enc) //创建使用给定字符集编码器的 OutputStreamWriter。

注意:InputStreamReaderOutputStreamWriter实现从字节流到字符流之间的转换,使得流的处理效率得到提升,但是如果我们想要达到最大的效率,我们应该考虑使用缓冲字符流包装转换流的思路来解决问题。

比如:BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

utStreamWriter(OutputStream out, CharsetEncoder enc) //创建使用给定字符集编码器的 OutputStreamWriter。

参考链接:
Java IO流学习总结
java输入输出流详细讲解(入门经典),详细讲解JAVA中的IO流

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值