编程的蜗牛

颓废,始于首次的懒惰与原谅。

导航

Java基础-IO流(2)

(参考博客:https://blog.csdn.net/zhaoyanjun6/article/details/54972773

一、缓冲流

  为何要使用缓冲流?

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

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

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

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

  总结:

  •   BufferedInputStream 是缓冲输入流。它继承于FilterInputStream。
  •   BufferedInputStream 的作用是为另一个输入流添加一些功能,例如,提供“缓冲功能”以及支持mark()标记和reset()重置方法。
  •   BufferedInputStream 本质上是通过一个内部缓冲区数组实现的。例如,在新建某输入流对应的BufferedInputStream后,当我们通过read()读取输入流的数据时,BufferedInputStream会将该输入流的数据分批的填入到缓冲区中。每当缓冲区中的数据被读完之后,输入流会再次填充数据缓冲区;如此反复,直到我们读完输入流数据位置。

  (1)字节缓冲流

  1. BufferInputStream缓冲输入流

  1)构造函数

BufferedInputStream(InputStream in) //使用默认buf大小、底层字节输入流构建bis 
BufferedInputStream(InputStream in, int size) //使用指定buf大小、底层字节输入流构建bis 

  2)常用方法

int available();  //返回底层流对应的源中有效可供读取的字节数      
void close();  //关闭此流、释放与此流有关的所有资源  
boolean markSupport();  //查看此流是否支持mark
void mark(int readLimit); //标记当前buf中读取下一个字节的下标  
int read();  //读取buf中下一个字节  
int read(byte[] b, int off, int len);  //读取buf中下一个字节  
void reset();   //重置最后一次调用mark标记的buf中的位子  
long skip(long n);  //跳过n个字节、 不仅仅是buf中的有效字节、也包括in的源中的字节

  2. BufferOutputStream缓冲输出流

  1)构造函数

BufferedOutputStream(OutputStream out); //使用默认大小、底层字节输出流构造bos。默认缓冲大小是 8192 字节( 8KB )
BufferedOutputStream(OutputStream out, int size);  //使用指定大小、底层字节输出流构造bos

  2)常用方法

//在这里提一句,`BufferedOutputStream`没有自己的`close`方法,当他调用父类`FilterOutputStrem`的方法关闭时,会间接调用自己实现的`flush`方法将buf中残存的字节flush到out中,再`out.flush()`到目的地中,DataOutputStream也是如此。 
void  flush();  将写入bos中的数据flush到out指定的目的地中、注意这里不是flush到out中、因为其内部又调用了out.flush()  
write(byte b);  将一个字节写入到buf中  
write(byte[] b, int off, int len);  将b的一部分写入buf中 

  3. 实例操作,复制文件,操作:使用缓存流将F盘根目录里面名字为:123.png 图片复制成 abc.png。

复制代码
public class A3 {
    public static void main(String[] args) throws IOException {
        String filePath = "F:/123.png" ;
        String filePath2 = "F:/abc.png" ;
        File file = new File( filePath ) ;
        File file2 = new File( filePath2 ) ;
        copyFile( file , file2 );
    }
    
    public static void copyFile( File oldFile , File newFile){
        InputStream inputStream = null ;
        BufferedInputStream bufferedInputStream = null ;

        OutputStream outputStream = null ;
        BufferedOutputStream bufferedOutputStream = null ;
        try {
            inputStream = new FileInputStream( oldFile ) ;
            bufferedInputStream = new BufferedInputStream( inputStream ) ;

            outputStream = new FileOutputStream( newFile ) ;
            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();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        }finally {

            if( bufferedOutputStream != null ){
                try {
                    bufferedOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if( bufferedInputStream != null){
                try {
                    bufferedInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            
            if( inputStream != null ){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            
            if ( outputStream != null ) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}
复制代码

  (2)字符缓冲流

  1. BufferedReader

  1) 构造方法

BufferedReader(Reader in, int sz) //创建一个使用指定大小输入缓冲区的缓冲字符输入流。 
BufferedReader(Reader in) //创建一个使用默认大小输入缓冲区的缓冲字符输入流。

  2) 常用方法

复制代码
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() 操作(它一定支持)。
复制代码

  2. BufferedWriter

  1) 构造方法

BufferedWriter(Writer out, int sz) //创建一个使用给定大小输出缓冲区的新缓冲字符输出流。

BufferedWriter(Writer out) //建一个使用默认大小输出缓冲区的缓冲字符输出流。

  2) 常用方法

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) //写入字符串的某一部分。

  3. 实例操作

复制代码
public class A4 {
    public static void main(String[] args) {
        String filePath = "F:/123.txt" ;
        String filePath2 = "F:/abc.txt" ;

        File file = new File( filePath ) ;
        File file2 = new File( filePath2 ) ;
        copyFile( file , file2 );
    }

    private static void copyFile( File oldFile , File newFile ){
        Reader reader = null ;
        BufferedReader bufferedReader = null ;

        Writer writer = null ;
        BufferedWriter bufferedWriter  = null ;
        try {
            reader = new FileReader( oldFile ) ;
            bufferedReader = new BufferedReader( reader ) ;

            writer = new FileWriter( newFile ) ;
            bufferedWriter = new BufferedWriter( writer ) ;

            String result = null ; //每次读取一行的内容
            while (  (result = bufferedReader.readLine() ) != null ){
                bufferedWriter.write( result );  //把内容写入文件
                bufferedWriter.newLine();  //换行,result 是一行数据,所以没写一行就要换行 
            }

            bufferedWriter.flush();  //强制把数组内容写入文件

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                bufferedWriter.close();  //关闭输出流
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                bufferedReader.close();  //关闭输入流
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
复制代码

二、ByteArrayInputStream、ByteArrayOutPutStream

ByteArrayInputStream 可以将字节数组转化为输入流 。
ByteArrayOutputStream可以捕获内存缓冲区的数据,转换成字节数组。

  1. ByteArrayInputStream

  构造方法:

public ByteArrayInputStream(byte buf[])
public ByteArrayInputStream(byte buf[], int offset, int length)

  常用方法:

void  close() // 关闭该流并释放与之关联的所有资源。
String getEncoding() //返回此流使用的字符编码的名称。
int read()  //读取单个字符。
int read(char[] cbuf, int offset, int length) //将字符读入数组中的某一部分。
boolean ready() //判断此流是否已经准备好用于读取。

  2. ByteArrayOutputStream

  构造方法:

public ByteArrayOutputStream()
public ByteArrayOutputStream(int size)

  常用方法:

void write(int b)
void write(byte b[], int off, int len)
void writeTo(OutputStream out)
byte toByteArray()[]
void close()

  3. 实例测试

复制代码
//字节流ByteArrayInputStream的读写过程测试
package
com.app; import java.io.ByteArrayInputStream; import java.io.IOException; public class A7 { public static void main(String[] args) { String mes = "hello,world" ; byte[] b = mes.getBytes() ; ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( b ) ; int result = -1 ; while( ( result = byteArrayInputStream.read() ) != -1{ System.out.println( (char) result ); } try { byteArrayInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } }
复制代码
复制代码
//将ByteArrayOutputStream读出的字节流用FileOutputStream写入文件
package
com.app; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class A6 { public static void main(String[] args) { String mes = "你好,world" ; byte[] b = mes.getBytes() ; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream() ; try { byteArrayOutputStream.write( b ); FileOutputStream fileOutputStream = new FileOutputStream( new File( "F:/123.txt" ) ) ; byteArrayOutputStream.writeTo( fileOutputStream ) ; fileOutputStream.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); }catch (IOException e) { e.printStackTrace(); }finally{ try { byteArrayOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }
复制代码

三、转换流

  1. InputStreamReader

  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。

  一般方法:

void  close() // 关闭该流并释放与之关联的所有资源。
String    getEncoding() //返回此流使用的字符编码的名称。
int     read()  //读取单个字符。
int     read(char[] cbuf, int offset, int length) //将字符读入数组中的某一部分。
boolean  ready() //判断此流是否已经准备好用于读取。

  2. OutPutStreamWriter

  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。

  一般方法:

void  write(int c)   //写入的字符长度
void  write(char cbuf[])  //写入的字符数组
void  write(String str)  //写入的字符串
void  write(String str, int off, int len)  //应该写入的字符串,开始写入的索引位置,写入的长度
void  close() //关闭该流并释放与之关联的所有资源。

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

  3. 实例测试

复制代码
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
public class A5 {
    public static void main(String[] args) {
        String filePath = "F:/123.txt" ;
        String filePath2 = "F:/abc.txt" ;
        File file = new File( filePath ) ;
        File file2 = new File( filePath2 ) ;
        copyFile( file , file2 );
    }
    private static void copyFile( File oldFile , File newFile ){
        InputStream inputStream = null ;
        InputStreamReader inputStreamReader = null ;

        OutputStream outputStream = null ;
        OutputStreamWriter outputStreamWriter = null ;
        try {
            inputStream = new FileInputStream( oldFile ) ; //创建输入流
            inputStreamReader = new InputStreamReader( inputStream ) ; //创建转换输入流
            outputStream = new FileOutputStream( newFile ) ; //创建输出流
            outputStreamWriter = new OutputStreamWriter( outputStream ) ; //创建转换输出流
            int result = 0 ;
            while( (result = inputStreamReader.read()) != -1){  //一次只读一个字符
                outputStreamWriter.write( result ); //一次只写一个字符
            }
            outputStreamWriter.flush();  //强制把缓冲写入文件
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        }finally{
            if ( outputStreamWriter != null) {
                try {
                    outputStreamWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if ( inputStreamReader != null ) {
                try {
                    inputStreamReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}
复制代码

 

流的类型多而复杂,死记硬背是不可取的,用的时候请查阅:http://www.51gjie.com/java/1164.html

posted on   粼溪  阅读(43)  评论(0编辑  收藏  举报

努力加载评论中...
点击右上角即可分享
微信分享提示