飞道的博客

一文带你入门Java之I/O流

410人阅读  评论(0)

一、IO流的概述

1. 流的类型

  1. 操作数据单位:字节流、字符流
  2. 数据的流向:输入流、输出流
  3. 流的角色:节点流、处理流
    图解
    以字体颜色划分类别

2. 体系结构

重点学习蓝色框中的内容

3. 输入、输出的基本步骤

输入过程

  1. 创建File类的对象,指明读取的数据的来源。(要求此文件一定要存在)
  2. 创建相应的输入流,将File类的对象作为参数,传入流的构造器中
  3. 具体的读入过程: 创建相应的byte[] 或 char[]。
  4. 关闭流资源
    说明:程序中出现的异常需要使用try-catch-finally处理。

输出过程

  1. 创建File类的对象,指明写出的数据的位置。(不要求此文件一定要存在)
  2. 创建相应的输出流,将File类的对象作为参数,传入流的构造器中
  3. 具体的写出过程: write(char[]/byte[] buffer,0,len)
  4. 关闭流资源
    说明:程序中出现的异常应使用try-catch-finally处理。

二、字符流

字符流只能处理文本文件(例如:.txt,.java,.c,.cpp)。

1. 字符输入流

@Test public void testFileReader() {
        FileReader fr = null;

        try {
            //1. File的实例化
            File file = new File("testFileReader.txt");
            //2. 实例化 FileReader流
            fr = new FileReader(file);
            //3. 进行读入操作
            //read(char[] charbuffer):返回每次读入到数组中的字符个数,若达到文件末尾则返回-1
            char[] charbuffer = new char[5];
            int len;
            while ((len = fr.read(charbuffer)) != -1) {
                //方式一:
                //for (int i = 0; i < len; i++) {
                //    System.out.print(charbuffer[i]);
                //}
                //方式二:
                String str = new String(charbuffer, 0, len);
                System.out.print(str);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //4. 流的关闭
            if (fr != null) {
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

2. 字符输出流

@Test public void testFileWriter() {
        //1. File的实例化
        File file = new File("testFileWriter.txt");
        FileWriter fw = null;
        try {
            //2. FileWriter
            fw = new FileWriter(file);
            //3. 进行写出操作
            fw.write("Hello, ");
            fw.write("world ! ");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4. 流的关闭
            if (fw != null) {
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

三、字节流

字节流可处理所有文件

字节输入流/字节输出流

运用两种字节流进行文件复制操作

public void fileInputOutputStreamTest() throws IOException {
        //1. 创建File类对象,指定读入与写出的文件
        File srcFile = new File("img1.jpg");
        File destFile = new File("copy.jpg");
        //2. 创建输入输出流
        FileInputStream fileInputStream = new FileInputStream(srcFile);
        FileOutputStream fileOutputStream = new FileOutputStream(destFile);
        //3. 数据的读入与写出操作
        byte[] buffer = new byte[1024];
        //记录字符个数
        int len;
        while ((len = fileInputStream.read(buffer)) != -1) {
            //每次写出len个字符
            fileOutputStream.write(buffer, 0, len);
        }
        //4.关闭流 - 建议从后向前关闭流
        fileOutputStream.close();
        fileInputStream.close();
    }

四、缓冲流

  • BufferedInputStream
  • BufferedOutputStream
  • BufferedReader
  • BufferedWriter

缓冲流作用:提供流的读取、写入的速度
提高读写速度的原因:内部提供了一个缓冲区。默认情况下是8kb

1. 字符缓冲流

 @Test
    public void testBufferedReaderWriter() throws IOException {
        //1.实例化文件和流
        BufferedReader br = new BufferedReader(new FileReader(new File("hello.txt")));
        BufferedWriter bw = new BufferedWriter(new FileWriter(new File("copy.txt")));
        //2.进行数据读写
        char[] charbuffer = new char[1024];
        int len;
        while((len = br.read(charbuffer)) != -1){
            bw.write(charbuffer,0,len);
        }
        //3. 关闭资源
        bw.close();
        br.close();

    }

2. 字节缓冲流

 @Test
    public void copyFileWithBuffered() throws IOException {
        //1. 创建File类对象,指定读入与写出的文件
        File srcFile = new File("img1.jpg");
        File destFile = new File("copy.jpg");
        //2. 创建输入输出流
        InputStream fileInputStream = new FileInputStream(srcFile);
        FileOutputStream fileOutputStream = new FileOutputStream(destFile);
        //3. 创建缓冲流
        BufferedInputStream bis = new BufferedInputStream(fileInputStream);
        BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);
        //4. 数据的读入与写出操作
        byte[] buffer = new byte[1024];
        //记录字符个数
        int len;
        while ((len = fileInputStream.read(buffer)) != -1) {
            //每次写出len个字符
            bos.write(buffer, 0, len);
        }
        //5.关闭流 - 建议从后向前关闭流
        bos.close();
        bis.close();
    }

五、字符转换流

由于字符存在编码问题,转换流用于解决字符转码问题。

1. 输入字符转换流

@Test public void inputStreamReaderTest() throws IOException {

        FileInputStream fis = new FileInputStream("hello.txt");
        //InputStreamReader isr = new InputStreamReader(fis);//使用系统默认的字符集
        //参数2指明了字符集,具体使用哪个字符集,取决于文件dbcp.txt保存时使用的字符集
        //使用系统默认的字符集 默认为 UTF-8
        InputStreamReader isr = new InputStreamReader(fis, "UTF-8");

        char[] cbuf = new char[20];
        int len;
        while ((len = isr.read(cbuf)) != -1) {
            String str = new String(cbuf, 0, len);
            System.out.print(str);
        }
        isr.close();
    }

2. 输出字符转换流

该例子为综合输入和输出字符转换流

@Test 
public void outputStreamWriterTest() throws Exception {
        //1.造文件、造流
        File file1 = new File("hello.txt");
        File file2 = new File("hello_gbk.txt");

        FileInputStream fis = new FileInputStream(file1);
        FileOutputStream fos = new FileOutputStream(file2);

        InputStreamReader isr = new InputStreamReader(fis, "utf-8");
        OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk");

        //2.读写过程
        char[] cbuf = new char[20];
        int len;
        while ((len = isr.read(cbuf)) != -1) {
            osw.write(cbuf, 0, len);
        }

        //3.关闭资源
        isr.close();
        osw.close();

    }

六、对象流

自定义类型的对象使用对象流的条件:

  1. 需要实现接口:Serializable
  2. 当前类提供一个全局常量:serialVersionUID
  3. 除了当前类需要实现Serializable接口之外,还必须保证其内部所属性也必须是可序列化的。(默认情况下,基本数据类型可序列化)

补充:ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量

import org.junit.Test;
import java.io.*;

public class ObjectInputOutputStreamTest {

	/**
     * 对象输出流
     */
    @Test 
    public void objectOutputStreamTest() {
        ObjectOutputStream oos = null;

        try {
            //1.
            oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
            //2.
            oos.writeObject(new String("I like Java"));
            oos.flush();//刷新操作

            oos.writeObject(new Student("张三", 23));
            oos.flush();

            oos.writeObject(new Student("李四", 23, 1001));
            oos.flush();

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (oos != null) {
                //3.
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }
    }
	/**
     * 对象输入流
     */
    @Test 
    public void objectInputStreamTest() {
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream("object.dat"));

            Object obj = ois.readObject();
            String str = (String)obj;

            Student student = (Student)ois.readObject();
            Student student1 = (Student)ois.readObject();

            System.out.println(str);
            System.out.println(student);
            System.out.println(student1);

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

            }
        }
    }
}
//实体类/自定义类型
class Student implements Serializable{

    private static final long serialVersionUID = -121294470754667710L;
    
    private String name;
    private int age;
    private int score;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Student(String name, int age, int score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    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 "Student{" + "name='" + name + '\'' + ", age=" + age + ", score=" + score + '}';
    }
}

七、RandomAccessFile/随机存取文件流

  1. RandomAccessFile直接继承于java.lang.Object类,实现了DataInput和DataOutput接口。
  2. RandomAccessFile既可以作为一个输入流,又可以作为一个输出流
  3. 如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。
    如果写出到的文件存在,则会对原文件内容进行覆盖。(默认情况下,从头覆盖)
  4. 可以通过seek(int pos) ,实现RandomAccessFile插入数据的效果。
import org.junit.Test;

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

public class RandomAccessFileTest {

    /**
     * 实现复制粘贴
     * @throws IOException
     */
    @Test public void randomAccessFileTest1() throws IOException {

        //1.创建流
        RandomAccessFile raf1 = new RandomAccessFile(new File("img.jpg"), "r");
        RandomAccessFile raf2 = new RandomAccessFile(new File("img1.jpg"), "rw");
        //2.创建缓冲区
        byte[] buffer = new byte[1024];
        int len;
        while ((len = raf1.read(buffer)) != -1) {
            raf2.write(buffer, 0, len);
        }
        //3.关闭流
        raf1.close();
        raf2.close();
    }

    /**
     * 使用RandomAccessFile实现数据的插入效果
     */
    @Test public void randomAccessFileTest2() throws IOException {

        RandomAccessFile raf1 = new RandomAccessFile("hello.txt", "rw");
        //将指针调到角标为3的位置
        raf1.seek(3);
        //保存指针3后面的所数据到StringBuilder中
        StringBuilder builder = new StringBuilder((int)new File("hello.txt").length());
        byte[] buffer = new byte[20];
        int len;
        while ((len = raf1.read(buffer)) != -1) {
            builder.append(new String(buffer, 0, len));
        }
        //调回指针
        raf1.seek(3);
        raf1.write("AAA".getBytes());

        //将StringBuilder中的数据写入到文件中
        raf1.write(builder.toString().getBytes());
        raf1.close();
    }
}

八、Path、Paths、Files的使用

1. Path

Path用于替换原有的File类。
该接口的实现是不可变且安全的,可供多个并行线程使用。

2. Paths

此类仅由静态方法组成,通过转换路径字符串返回Path或URI 。

Paths类提供了get()方法用来获取Path对象。

Paths的常用方法

3. Files

主要用于操作文件或文件目录的工具类
常用方法


转载:https://blog.csdn.net/qq_26020387/article/details/106157373
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场