Java IO流

I/O(Input / Output):用于设备之间的数据传输,如读写文件,网络通讯等。

1. 分类

1.1 字节流、字符流

按操作数据单位不同分类:字节流(8 bit)、字符流(16 bit)

1.1.1 字节流

以字节为单位,处理2进制文件,如图片、声音、影像等文件
抽象基类:InputStream、OutputStream

1.1.2 字符流

以字符为单位,读文本、数字等类型的文件
抽象基类:Reader、Writer

1.2 节点流、处理流

按流的角色的不同分类:节点流(作用在文件上)、处理流(作用在已有流外层的流)

1.3 输入流、输出流

按数据流向不同分类:输入流、输出流(以程序/内存为视点)

2. 节点流(文件流)

FileInputStream、FileOutputStream
FileReader、FileWriter
(最基本的流,效率略差,开发中并不常用)

public class FileReaderWriterTest {
    // 空参read(),每次搬运一个字符
    @Test
    public void test01() {
        FileReader fr = null;
        try {
            // 1.指明要操作的文件
            File file = new File("hello.txt");
            // 2.提供具体的流(流的实例化)
            fr = new FileReader(file);
            // 3.读取数据,返回一个字符或-1
            //        int read = fr.read();
            //        while (read != -1){
            //            System.out.println((char)read);
            //            read = fr.read();
            //        }
            int read;
            while ((read = fr.read()) != -1){
                System.out.println((char)read);
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            if(fr != null) {
                try {
                    // 4.关闭流
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    // 带数组参数的read(),每次搬运数组长度个数据(例:字符)
    @Test
    public void test02(){
        FileReader fr = null;
        try {
            // 1.指明要操作的文件
            File file = new File("hello.txt");
            // 2.提供具体的流(流的实例化)
            fr = new FileReader(file);
            // 3.读取数据,返回每次读取到的字符个数或-1
            int len;
            char[] chBuff = new char[5];
            while ((len = fr.read(chBuff)) != -1){
//                for (int i = 0; i < len; i++) {
//                    System.out.println(chBuff[i]);
//                }
                String str = new String(chBuff,0,len);
                System.out.println(str);
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            if(fr != null) {
                try {
                    // 4.关闭流
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    @Test
    public void test03() {
        FileWriter fileWriter = null;
        try {
           // 1.指明要操作的文件
           File file = new File("hello.txt");
           // 2.提供具体的流(流的实例化)
           fileWriter = new FileWriter(file,true);
           // 3.读取数据,返回每次读取到的字符个数或-1
           fileWriter.write("Hello IO \n");
           fileWriter.write("Hello WRITE");
       }catch (IOException e){
            e.printStackTrace();
        }finally {
            // 4.关闭流
            if (fileWriter != null) {
                try {
                    fileWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    @Test
    public void test04(){
        FileReader fr = null;
        FileWriter fw = null;
        try {
            // 1.指明要操作的文件
            File readFile = new File("hello.txt");
            File writeFile = new File("hello1.txt");
            // 2.提供具体的流(流的实例化)
            fr = new FileReader(readFile);
            fw = new FileWriter(writeFile,true);
            // 3.读取和写入操作
            char[] cbuf = new char[5];
            int len;
            while ((len = fr.read(cbuf)) != -1){
                fw.write(cbuf,0,len);
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            // 4.关闭流
            try {
                if(fw != null)
                    fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                if(fr != null)
                    fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    @Test
    public void test05(){
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            // 1.指明要操作的文件
            File readFile = new File("a.jpg");
            File writeFile = new File("b.jpg");
            // 2.提供具体的流(流的实例化)
            fis = new FileInputStream(readFile);
            fos = new FileOutputStream(writeFile,true);
            // 3.读取和写入操作
            byte[] bbuf = new byte[5];
            int len;
            while ((len = fis.read(bbuf)) != -1){
                fos.write(bbuf,0,len);
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            // 4.关闭流
            try {
                if(fis != null)
                    fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(fos != null)
                    fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

3. 处理流

处理流是对已有流的包装。

3.1 缓冲流

缓冲流的作用:内部提供缓冲区,先将读取到的数据放到缓冲区,然后一次写出,从而可以提高文件的读写效率。
BufferedInputStream、BufferedOutputStream
BufferedReader、BufferedWriter

public class BufferedTest {
    @Test
    public void bufferedCharStreamTest(){
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            // 1.指明要操作的文件
            File readFile = new File("a.jpg");
            File writeFile = new File("c.jpg");
            // 2.提供具体的流(流的实例化)
            // 2.1 节点流
            FileInputStream fis = new FileInputStream(readFile);
            FileOutputStream fos = new FileOutputStream(writeFile,true);
            // 2.2 缓冲流
            bis = new BufferedInputStream(fis);
            bos = new BufferedOutputStream(fos);
            // 3.读取和写入操作
            byte[] bbuf = new byte[5];
            int len;
            while ((len = bis.read(bbuf)) != -1){
                bos.write(bbuf,0,len);
                //bos.flush(); // 刷新缓冲区,写出,默认是缓冲区满了之后自动刷新(输出)
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            // 4.关闭流(先关闭外层再关闭内层,由于关闭外层会自动关闭内存,所以内存关闭可省略)
            try {
                if(bis != null)
                    bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(bos != null)
                    bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    @Test
    public void bufferedByteStreamTest(){
        BufferedReader br = null;
        BufferedWriter bw = null;
        try {
            // 1.指明要操作的文件
            // 2.提供具体的流(流的实例化)
            // 2.1 节点流
            // 2.2 缓冲流
            br = new BufferedReader(new FileReader(new File("hello.txt")));
            bw = new BufferedWriter(new FileWriter(new File("hello2.txt"),true));
            // 3.读取和写入操作
            char[] bbuf = new char[5];
            int len;
            while ((len = br.read(bbuf)) != -1){
                bw.write(bbuf,0,len);
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            // 4.关闭流(先关闭外层再关闭内层,由于关闭外层会自动关闭内存,所以内存关闭可省略)
            try {
                if(br != null)
                    br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(bw != null)
                    bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

3.2 转换流

字节流和字符流之间的转换。

    public void test01(){
        InputStreamReader isr = null;
        OutputStreamWriter osw = null;
        try {
            // 字节流读入
            FileInputStream fis = new FileInputStream("hello.txt");
            // 字节流输出
            FileOutputStream fos = new FileOutputStream("hello_gbk.txt");
            // 字节流转字符流(解码)
            isr = new InputStreamReader(fis); // 默认字符集(IDE),自定义字符集(fis,"UTF-8"),取决于读取的文件保存类型
            // 字符流转字节流(编码)
            osw = new OutputStreamWriter(fos,"gbk");
            char[] cbuf = new char[5];
            int len;
            while ((len = isr.read(cbuf)) != -1){
                String str = new String(cbuf,0,len);
                osw.write(cbuf,0,len);
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            if(isr != null){
                try {
                    isr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(osw != null){
                try {
                    osw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

4. 对象流

用于存储和读取基本类型或对象的处理流。

4.1 序列化

序列化:将数据从内存保存到数据源;ObjectOutputStream
反序列化:将数据从数据源还原成内存对象;ObjectInputStream

对象的序列化机制:
允许把内存中Java 对象转换成与平台无关的二进制流,从而允许把这种二进制流持久化保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点,当其他程序获取了这种二进制流,就可以恢复成原来的Java 对象

4.2 代码实现

public class ObjectInputOutputTest {
    /**
     * 序列化:Java 对象保存到硬盘或通过网络传输
     * ObjectOutputStream
     */
    @Test
    public void objectOutputStreamTest(){
        ObjectOutputStream oos = null;
        try {
            oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
            oos.writeObject(new String("Hello ObjectInputOutputTest"));
            oos.writeObject(new Person("chengyu",30));
            oos.flush(); // 刷新操作
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            if(oos != null){
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    /**
     * 反序列化:硬盘或通过网络传输的对象还原为Java 对象
     * ObjectInputStream
     */
    @Test
    public void objectInputStreamTest(){
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream("object.dat"));
            String str = (String)ois.readObject();
            Person p = (Person)ois.readObject();
            System.out.println(str);
            System.out.println(p);
        }catch (IOException e){
            e.printStackTrace();
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        }finally {
            if(ois != null){
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
// 1. 实现Serializable 可序列化标识接口
// ※序列化对象的所有属性也要求是可序列化
class Person implements Serializable{
    // 2.提供全局常量(唯一标识)
    // 若不定义的情况下,系统会自动生成,但存在问题,若序列化后更改了序列化对象类,直接反序列化将出现问题,因为修改后的序列化对象的唯一标识也自动更新了
    private static final long serialVersionUID = -1149794470754667710L;
    private String name;
    private int age;
    public Person() {
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

补充:static 和transient 修饰的成员变量无法序列化,static 为全局的,而transient 则用于标记指定内容不允许序列化

5. 随机存取文件流

RandomAccessFile 类
既可以做输入流也可以做输出流,直接继承于Object 类;写文件时覆盖文件部分内容。

public class RandomAccessFileTest {
    @Test
    public void test01(){
        RandomAccessFile raf1 = null;
        RandomAccessFile raf2 = null;
        try {
            raf1 = new RandomAccessFile("hello.txt","r");// 访问模式r:只读;rw:读写;rwd:读写,同步文件内容;rws:读写,同步文件内容及元数据
            raf2 = new RandomAccessFile("hello3.txt","rw");
            byte[] buffer = new byte[1024];
            int len;
            while ((len = raf1.read(buffer)) != -1){
                raf2.write(buffer,0,len);
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            if(raf2 != null){
                try {
                    raf2.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(raf1 != null){
                try {
                    raf1.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    @Test
    public void test02(){
        RandomAccessFile raf = null;
        try {
            raf = new RandomAccessFile("hello3.txt","rw");
            raf.seek(5); // 从目标文件的角标为5 的位置进行覆盖
            raf.write("abc".getBytes());
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            if(raf != null){
                try {
                    raf.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

6. NIO.2 (java 7)

6.1 介绍

NIO是Java 1.4推出的一套新的IO API,支持面向缓冲区的(IO 是面向流的)、基于通道的IO 操作,更加高效的方式进行文件的读写操作。但使用上并不方便,在Java 7发布了NIO2。

早期Java 只提供了一个File 类来访问文件系统,但File 类的功能比较有限,性能也不高,大多数出错时也并不会提供异常信息;NIO.2 引入Path 结构,替换原有的File 类。

6.2 核心 API

记得操作文件、目录要使用Path 类和Files 类即可。

6.2.1 Path

用于替换File 类。

6.2.2 Files

用于操作文件或目录的工具类。

7. 其他流

标准输入输出流(了解)

System.in:键盘输入
System.out:控制台输出

打印流(了解)

将基本数据类型的数据格式转化为字符串输出。
PrintStream
PrintWriter

数据流(了解)

操作基本数据类型和String 类型的数据。持久化到文件中或从文件中读取。
DataInputStream
DataOutputStream

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值