java 基础I/O

IO流

1.流的概念和作用

​ 流是一组有序的,有起点和终点的字节的集合,是对数据传输的总称或者抽象说法。即数据在两个设备之间传输称为流,流的本质是数据传输;

分类
  • 按处理数据单元分类

    • 字节流:以字节单位获取数据,命名上以stream结尾的流一般是字节流,eg:FileInputStream,FileOutputStream

    • 字符流:以字符为单位获取数据,命名上以Reader/Writer结尾的流一般是字符流,eg:FileReader,FileWriter

    • 区别:

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

      (2):处理对象不同,字节流能处理所有类型的数据,图片,avi等;字符流只能处理字符类型的数据;

    • 结论:只要是纯文本输出 使用字符流,除此之外都是用字节流;

  • 按处理对象不同分类

    • 节点流:可以直接从数据源或目的地读写数据

      操作文件操作数组操作字符串操作管道
      FileInputStreamByteArrayInputStreamStringReaderPipedInputStream
      FileOutputStreamByteArrayOutputStreamStringWriterPipedOutputStream
      FileReaderCharArrayReader/PipedReader
      FileWriterCharArrayWriter/PipedWriter
    • 处理流:也叫缓冲流,不直接链接到数据源或者目地,使用在节点流上的流称为处理流,通过对其他流的处理提升程序性能,处理流的构造方法总要带一个其他流的对象作为参数,一个流的对象经过其他流的包装称为流的链接。

    ​ (1):缓冲流:BufferedInputStream,BufferedOutputStream ,BufferReader,BufferWriter增加缓冲功能,避免频繁读写硬盘。

    ​ (2)转换流:InputStreamReader,OutputStreamReader 实现了字节流和字符流之间的转换。

    ​ (3):数据流:DataInputStream,DataOutputStream 等将其他基础数据类型写入到文件中,或者读取出来。

    • 转换流:

      InputStreamReader,OutputStreamWriter 需要InputStream或OutputStream作为参数,实现从字节流到到字符流的转换。

    • 节点流处于IO操作的第一线,所有操作必须通过他们进行;处理流可以对节点流进行包装,提高性能或者提高程序的灵活性

    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N8x274UE-1620533981839)(C:\Users\Mr.zhang\Desktop\截图\stream.png)]

2.四大抽象类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uTj1jp47-1620533981842)(C:\Users\Mr.zhang\Desktop\截图\io1.png)]

  • InputStream 是所有输入字节流的父类,抽象类
    • ByteArrayInputStream从byte数组中读取数据
    • StringBufferInputStream从StringBuffer中读取数据
    • FileInputStream从本地文件中读取数据
    • ObjectInputStream和所有FileInputStream的子类都是装饰流
  • OutputStream 操作字节输出流
    • ByteArrayOutputStream,FileOutputStream是两种基本的介质流,分别向Byte数组和本地文件中写入数据
  • Reader操作字符输入流
  • Writer操作字符输出流

3.总结

  • 输入流:InputStream和Reader,从文件读取 到程序中
  • 输出流:OutputStream和Writer ,从程序中写入到文件

4.FileInputStream,FileOutputStream,读写取文件内容。

    public static void main(String[] args) {
        String filePath =  "C:\\Users\\Mr.zhang\\Desktop\\MarkDown\\ioTest\\iotest.txt";

        //测试写入文件
        writeFile(filePath,"今天也是做好人的一天,你很好");

        //测试从文件中读取内容
        System.out.println(readFile(filePath));




    }


    /**
     * 将content写入指定文件
     * @param filePath
     * @param content
     */
    public static void writeFile(String filePath,String content){
        FileOutputStream fileOutputStream = null;

        try {
            //1.根据文件路径创建输出流
            fileOutputStream = new FileOutputStream(filePath);

            //2.把String转换成byte数组
            byte[] bytes = content.getBytes();

            //3.把bytes数组写入输出流中
            fileOutputStream.write(bytes);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 读取文件内容
     * @return
     */
    public static String readFile(String filePath){
        FileInputStream fileInputStream = null;
        String result = "";

        try {
            //根据path路径实例化一个输入流的对象
            fileInputStream = new FileInputStream(filePath);

            //返回这个输入流可以被都剩下的bytes字节的剩余量
            int available = fileInputStream.available();
            //创建一个接收数组
            byte[] bytes = new byte[available];

            fileInputStream.read(bytes);

            result = new String(bytes);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return result;
    }

运行结果

今天也是做好人的一天,你很好

Process finished with exit code 0

5.File

文件和目录路径名的抽象表示,可以完成对所有文件的操作。

  • 构造

    public File(String pathname)  //文件的绝对路径
    public File(URI uri)  //文件的URI地址
    
    public File(String parent, String child)  //指定父文件绝对路径、子文件绝对路径
    public File(File parent, String child)  //指定父文件、子文件相对路径
    
    
    //下面这两个是File类中私有的构造函数,外面不能调用
    private File(String child, File parent)  
    private File(String pathname, int prefixLength) 
    
  • 感兴趣的方法 可以读取指定目录下的文件,可以通过FileFilter 过滤指定后缀的文件

    static void flieListFilter(){
        MyFileFlter myFileFlter =new MyFileFlter(".png");
        File file = new File("C:\\Users\\Mr.zhang\\Desktop\\截图");
    
        File[] files = file.listFiles(myFileFlter);
        for (File f : files) {
            System.out.println(f.getName());
        }
        
    }
    
    static class MyFileFlter implements FileFilter{
    
        String type;   //文件类型
    
        MyFileFlter(){
        }
        MyFileFlter(String type){
            this.type = type;
        }
    
    
        @Override
        public boolean accept(File pathname) {
            if(!pathname.isDirectory()){
                pathname.getName().endsWith(type);
                return true;
            }
            return false;
        }
    }
    

6.缓冲流BufferedInputStream,BufferOutputStream

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

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

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

现在就可以回答在本文的开头提出的问题:
BufferedInputStreamBufferedOutputStream类就是实现了缓冲功能的输入流/输出流。使用带缓冲的输入输出流,效率更高,速度更快。

BufferedInputStream本质上是通过一个内部缓冲区数组实现的,BufferInputStream会将输入流的数据分批填入缓冲区中,每当缓冲区的数据被读取完之后,输入流会再次填入到缓冲区,如此反复;

那么什么时候flush()才有效呢?
答案是:当OutputStream是BufferedOutputStream时。

当写文件需要flush()的效果时,需要
FileOutputStream fos = new FileOutputStream(“c:\a.txt”);
BufferedOutputStream bos = new BufferedOutputStream(fos);
也就是说,需要将FileOutputStream作为BufferedOutputStream构造函数的参数传入,然后对BufferedOutputStream进行写入操作,才能利用缓冲及flush()。

查看BufferedOutputStream的源代码,发现所谓的buffer其实就是一个byte[]。
BufferedOutputStream的每一次write其实是将内容写入byte[],当buffer容量到达上限时,会触发真正的磁盘写入。
而另一种触发磁盘写入的办法就是调用flush()了。

BufferedOutputStreamclose()时会自动flush
BufferedOutputStream在不调用close()的情况下,缓冲区不满,又需要把缓冲区的内容写入到文件或通过网络发送到别的机器时,才需要调用flush.

 public static void main(String[] args) {
        //复制图片
        copuFile("d:\\io2.png","C:\\Users\\Mr.zhang\\Desktop\\截图\\io1.png");

    }


    /**
     * 复制图片
     */
    static void copuFile(String newFilePath,String oldFilePath){

        InputStream inputStream = null;
        BufferedInputStream bis = null;

        OutputStream outputStream = null;
        BufferedOutputStream bos = null;


        File newFile = new File(newFilePath);
        File oldFile = new File(oldFilePath);

        try {
            inputStream = new FileInputStream(oldFile);   //创建一个输入流
            bis = new BufferedInputStream(inputStream);   //对接缓冲流


            outputStream = new FileOutputStream(newFile); //创建一个输出流
            bos = new BufferedOutputStream(outputStream); //对接缓冲流
 
            byte[] inputByte = new byte[1024];             //代表一次读取1kb 暂存从输入流读取的数据

            int temp = 0;  //代表实际读取的字节数
            while ((temp=bis.read(inputByte))!=-1){
                bos.write(inputByte,0,temp);
            }

            //主动刷新,将缓冲区的内容写入到文件
            bos.flush();

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

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

        }


    }

close()方法的作用

关闭输入流,并且释放系统资源
BufferedInputStream装饰一个 InputStream 使之具有缓冲功能,is要关闭只需要调用最终被装饰出的对象的 close()方法即可,因为它最终会调用真正数据源对象的 close()方法。因此,可以只调用外层流的close方法关闭其装饰的内层流。

7.缓冲流BufferedReader,BufferWriter

方法

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

Test

public static void main(String[] args) {

    copyFile("D:/newTest.txt","C:\\Users\\Mr.zhang\\Desktop\\MarkDown\\ioTest\\iotest.txt");

}


/**
 * 复制txt文件
 * @param newFileStr
 * @param oldFileStr
 */
static void copyFile(String newFileStr,String oldFileStr){

    FileReader fileReader = null;
    BufferedReader bufferedReader = null;

    FileWriter fileWriter = null;
    BufferedWriter bufferedWriter = null;

    File newFile = new File(newFileStr);
    File oldFile = new File(oldFileStr);

    try {
        fileReader = new FileReader(oldFile);               //创建FileReader读字符流
        bufferedReader = new BufferedReader(fileReader);    //接入缓冲流

        fileWriter = new FileWriter(newFile);            //创建FileWriter写字符流
        bufferedWriter = new BufferedWriter(fileWriter);    //接入缓冲流

        String result = null;    //每次读取内容
        while (( result = bufferedReader.readLine() ) != null){
            bufferedWriter.write(result);
            bufferedWriter.newLine();  //换行
        }
        bufferedWriter.flush();  //强制把数组内容写入文件

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }finally {

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


}

8.转换流 InputStreamReader,OutputStreamWriter

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

  • 构造

    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() //判断此流是否已经准备好用于读取。
    
    

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() //关闭该流并释放与之关联的所有资源。
    
public static void main(String[] args) {

    copyFile("D:/new2Test.txt","C:\\Users\\Mr.zhang\\Desktop\\MarkDown\\ioTest\\iotest.txt");

}

/**
 * 复制txt文件
 * @param newFileStr
 * @param oldFileStr
 */
static void copyFile(String newFileStr,String oldFileStr){

    InputStream inputStream = null;
    InputStreamReader  inputStreamReader = null;

    OutputStream outputStream = null;
    OutputStreamWriter outputStreamWriter = null;

    File newFile = new File(newFileStr);
    File oldFile = new File(oldFileStr);

    try {
        inputStream = new FileInputStream(oldFile);              //创建输入流
        inputStreamReader = new InputStreamReader(inputStream);  //创建转换输入流

        outputStream = new FileOutputStream(newFile);            //创建输出流
        outputStreamWriter = new OutputStreamWriter(outputStream);    //创建转换输出流

        int temp = 0;    //每次读取内容
        while (( temp = inputStreamReader.read() ) != -1){
            System.out.println(temp);
           outputStreamWriter.write(temp); //读取二进制数据
        }
        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();
            }
        }
    }

}
  1. 字节数组ByteArrayInputStream,ByteArrayOutputStream

ByteArrayInputStream 可以将字节数组转换为输入流;

ByteArrayOutputStream 可以捕获内存缓冲区中的数据,转换成字节数组;

  • 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() //判断此流是否已经准备好用于读取。
  String msg = "hello,world";
        byte[] b = msg.getBytes();
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(b);
        int temp = -1;

        while ((temp=byteArrayInputStream.read())!=-1){

            System.out.println((char)temp);

        }
        try {
            byteArrayInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }


    }

  • ByteArrayOutputStream

​ -构造

  ~~~java

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

    public static void main(String[] args) throws IOException {
        String mes = "你好,world" ;
        byte[] b = mes.getBytes() ;

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

        FileOutputStream fileOutputStream = null;


        try {
            byteArrayOutputStream.write(b);
            fileOutputStream = new FileOutputStream("D:/byteArrayoutputstreamTest.txt");
            byteArrayOutputStream.writeTo(fileOutputStream);

            fileOutputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(fileOutputStream!=null){
                fileOutputStream.close();
            }
            if(byteArrayOutputStream!=null){
                byteArrayOutputStream.close();
            }
        }
    }

10.FileUtils 工具类

Commons io

Apache Commons IO是Apache基金会创建并维护的Java函数库。它提供了许多类使得开发者的常见任务变得简单,同时减少重复代码,这些代码可能遍布于每个独立的项目中,你却不得不重复的编写。

在这里插入图片描述

这里集成有很多对文件操作的方法,包括对集合的操作;

  • 复制文件

  • 复制文件夹

  • 下载文件copyURLToFile(final URL source, final File destination)

  • 字符串写入文件writeStringToFile(final File file, final String data, final String encoding) writeStringToFile(final File file, final String data, final Charset encoding, final boolean append)

  • 把字节数组写入文件

    void writeByteArrayToFile(final File file, final byte[] data)
    
    void writeByteArrayToFile(final File file, final byte[] data, final boolean append)
    
    void writeByteArrayToFile(final File file, final byte[] data, final int off, final int len)
    
    void writeByteArrayToFile(final File file, final byte[] data, final int off, final int len,
                                                final boolean append)
    	
    
  • 把集合里面的内容写入文件

    void writeLines(final File file, final Collection<?> lines)
    
    void writeLines(final File file, final Collection<?> lines, final boolean append)
    
    void writeLines(final File file, final String encoding, final Collection<?> lines)
    
    void writeLines(final File file, final String encoding, final Collection<?> lines,
                                      final boolean append)
                                      
    void writeLines(final File file, final String encoding, final Collection<?> lines,
                                      final String lineEnding)
    
    void writeLines(final File file, final String encoding, final Collection<?> lines,
                                      final String lineEnding, final boolean append)
    
    void writeLines(final File file, final Collection<?> lines, final String lineEnding)
    
    void writeLines(final File file, final Collection<?> lines, final String lineEnding,
                                      final boolean append)
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值