Java-IO

428 阅读5分钟

IO简介

​ 数据流是一组有序,有起点和终点的字节的数据序列。包括输入流和输出流。

​ 流序列中的数据既可以是未经加工的原始二进制数据,也可以是经一定编码处理后符合某种格式规定的特定数据。因此Java中的流分为两种:
1、字节流:数据流中最小的数据单元是字节
2、 字符流:数据流中最小的数据单元是字符, Java中的字符是Unicode编码,一个字符占用两个字节。

​ Java.io包中最重要的就是5个类和一个接口。5个类指的是File、OutputStream、InputStream、Writer、Reader;一个接口指的是Serializable。掌握了这些就掌握了Java I/O的精髓了。

IO类结构

image.png

1、字节流的学习过程

image.png I/O的架构就是装饰模式(代理模式跟装饰模式的区别www.jianshu.com/p/c06a686da…)
装饰模式 主要是继承 并拓展、增强 image.png 以输出流为例:
OutputStream -> FileOutputStream/FilterOutputStream ->DataOutputStream->bufferedOutputStream

字节流实例

1、读写需要一一对应,不然容易出现乱码
2、读写都是对内存的操作
3、输出是指程序往文件传递数据,输入是磁盘文件往程序传入数据。 都是针对程序而言

字节流例子

package com.xm.studyproject.java.io;

import android.util.Log;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 字节流例子 数据流
 */
public class DataStreamTest {
    private static final String TAG = "DataStreamTest";

    //测试输入流 (就是将内存/磁盘中 读到输入流中 )
    void testDataInputStream(File file) {
        try {
            //FileInputStream extends InputStream
            //InputStream 并没有实现read方法 是暴漏出去了
            FileInputStream fileInputStream = new FileInputStream(file);
            //缓冲流 避免按字节一个个读到内存/磁盘中 DEFAULT_BUFFER_SIZE = 8192
            BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
            //数据的包装类 可以read各种基本类型的数据
            DataInputStream dataInputStream = new DataInputStream(bufferedInputStream);
            //读的时候需要跟写顺序保持一致  不然会出现错乱
            dataInputStream.readBoolean();
            dataInputStream.readBoolean();
            dataInputStream.readDouble();
            //字节地方不推荐使用读行
            //dataInputStream.readLine()
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //测试输出流 (就是将流内容输出到磁盘上 )
    void testDataOutputStream(File file) {
        try {
            //同上 OutputStream没有实现write方法
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
            DataOutputStream dataOutputStream = new DataOutputStream(bufferedOutputStream);
            dataOutputStream.writeBoolean(true);
            dataOutputStream.write(26);
            dataOutputStream.writeChars("测试数据");
            dataOutputStream.writeDouble(23.8);
            Log.i(TAG, "testDataOutputStream: "+dataOutputStream.toString());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

字节流的 缓冲流实例

package com.xm.studyproject.java.io;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 字节流的 缓冲流实例
 * 为了提升Stream的执行效率,所以出现了bufferedOutputStream。bufferedOutputStream就是将本地添加了一个缓存的数组。在使用bufferedOutputStream之前每次从磁盘读入数据的时候都是需要访问多少byte数据就向磁盘中读多少个byte的数据,而出现bufferedOutputSteam之后,策略就改了,会先读取整个缓存空间相应大小的数据,这样就是从磁盘读取了一块比较大的数据,然后缓存起来,从而减少了对磁盘的访问的次数以达到提升性能的目的。
 */
public class BufferStreamTest {

    private static final byte[] byteArray = {
            0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
            0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A
    };

    //从流到磁盘中
    void testBufferOutStream(File file) {
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);
            bos.write(byteArray[0]);
            bos.write(byteArray, 1, byteArray.length - 1);
            bos.flush();
            bos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    void bufferedInputStream(File file) {
        try {
            BufferedInputStream bin = new BufferedInputStream(new FileInputStream(file));
            for(int i = 0; i < 10; i++) {
                //bin.available() 还有数据情况下
                if (bin.available() >= 0) {
                }
            }

            //
            bin.mark(6666);
            bin.skip(10);

            byte[] b = new byte[1024];
            int n1 = bin.read(b, 0, b.length);
            System.out.println("ʣ�����Ч�ֽ��� �� " + n1);

            //回到mark位置
            bin.reset();
            int n2 = bin.read(b,0, b.length);
            System.out.println("ʣ�����Ч�ֽ��� �� " + n2);

        }catch (IOException e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }
}

## 字符流的学习

![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b53d1a57af12484ca251364e0d1d31eb~tplv-k3u1fbpfcp-zoom-1.image)

字符输入、输出流

package com.xm.studyproject.java.io;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
 * 字符输入、输出流
 */
public class BufferReaderWriterTest {

    void testBufferReader(File file) {
        try {
            FileReader fileReader = new FileReader(file);
            BufferedReader bufferedReader = new BufferedReader(fileReader);
            //单行字符串值默认是80
            //bufferedReader.readLine()
            char[] chars = new char[1024];
            //一次性读1024个字节 如果内容为空 返回值为-1
            while (bufferedReader.read(chars) != -1) {
                System.out.println("字符串"+chars.toString());
            }
            bufferedReader.close();

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

    void testBufferWriter(File file) {
        try {
            FileWriter fileWriter = new FileWriter(file);
            BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
            bufferedWriter.write("字符串");
            bufferedWriter.flush();
            bufferedWriter.close();

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

输入流 将字节流转化成字符流

package com.xm.studyproject.java.io;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

/**
 * 输入流 将字节流转化成字符流
 */
public class InputStreamReaderTest {
    void testInputStreamReader(File file) {
        try {
            FileInputStream fileInputStream = new FileInputStream(file);
            //字符字节转化流  编码格式
            InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"UTF-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            char[] chars = new char[1024];
            while (bufferedReader.read(chars) != -1) {
                System.out.println("字节流转化成字符流" + chars.toString());
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

RandomAccessFile

在分段下载中使用

package com.xm.studyproject.java.io;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;

/**
 * RandomAccessFile 注意啊跟InputStream和OutputStream没有任何关系
 * 好处:可以指定文件位置读写 所以就是我们可以 分段下载。通过seek( )方法
 * 特点1:RandomAccessFile不属于InputStream和OutputStream类系的它是一个完全独立的类,所有方法(绝大多数都只属于它自己)都是自己从头开始规定的,
 * 特点2:这里面包含读写两种操作  可设置只读等等模式
 */
public class RandomAccessFileTest {

    private static final File file = new File("src\\testtxt\\raf.txt");

    void testRandomAccessFile(File file) {
        //file有可能是文件也有可能是目录
        if (file.exists()) {
            file.delete();
        }
        //参数 mode 的值可选 "r":可读,"w" :可写,"rw":可读性
        try {
            RandomAccessFile rw = new RandomAccessFile(file, "rw");
            //seek(int index);可以将指针移动到某个位置开始读写;
            rw.seek(1000);
            //setLength(long len);给写入文件预留空间: 这块空间不可操作
            rw.setLength(1000);
            rw.read(new byte[100]);
            rw.writeChar('a');
            rw.writeChars("abcde");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}