Java 学习笔记(十一)IO 流

IO 流是有起点和终点的有序的字节序列

IO 流的分类

  • 输入流和输出流

    程序从外面读数据就是输入流,程序把数据保存到外面就是输出流

  • 字节流和字符流

    以字节为单位处理流中的数据就是字节流,以字符为单位处理流中的数据就是字符流

  • 节点流和处理流

    直接从设备读写数据就是节点流,处理流是对节点流的包装

FileInputStreamFileOutputStream

FileInputStream 流以字节为单位读取文件中的内容,FileOutputStream 流以字节为单位把数据保存到文件中。这一对流类可以读写所有格式的文件

import java.io.FileInputStream;
import java.io.IOException;

/**
 * FileInputStream 流的基本使用
 */
public class Test01 {
    public static void main(String[] args) throws IOException {
        // 通过 FileInputStream 的构造方法指定要读取的文件,文件内容:abcdef
        FileInputStream fis = new FileInputStream("/Users/Desktop/test");

        // 调用 available() 方法可以返回还有多少个字节未读
        System.out.println(fis.available());

        // 调用 read() 方法可以从文件中读取一个字节
        int bb = fis.read();
        System.out.println(bb);

        // 调用 skip() 方法可以跳过指定的字节数
        // 跳过2字节
        fis.skip(2);
        System.out.println(fis.available());

        System.out.println(fis.read());

        // 关闭流
        fis.close();
        
    }
}

输出内容:

6
97
3
100
import java.io.FileInputStream;
import java.io.IOException;

/**
 * 使用 FileInputStream 流读取文件的所有字节
 */
public class Test02 {
    public static void main(String[] args) throws IOException {
        // 通过构造方法指定要读取的文件
        FileInputStream fis = new FileInputStream("/Users/Desktop/test");

        // 调用 read() 方法读取一个字节,如果读到文件末尾会返回 -1
        int bb = fis.read();
        while (bb != -1) {
            System.out.println((char)bb);
            bb = fis.read();
        }

        // 关闭流
        fis.close();

    }
}

输出内容:

a
b
c
d
e
f
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;

/**
 * 使用 FileInputStream 流读取文件的字节,把读取到的字节保存到字节数组中
 */
public class Test03 {
    public static void main(String[] args) throws IOException {
        // 通过构造方法指定要读取的文件,文件内容:abcdef
        FileInputStream fis = new FileInputStream("/Users/Desktop/test");

        // 调用 read(byte[] b) 方法读取若干字节存储到 bytes 数组中,返回读到的字节数
        byte [] bytes = new byte[4];
        int len = fis.read(bytes);
        // 读取到4个字节
        System.out.println(len);
        // 输出结果:[97, 98, 99, 100]
        System.out.println(Arrays.toString(bytes));

        // 再继续读取文件
        len = fis.read(bytes);
        // 读取到2个字节
        System.out.println(len);
        // 输出结果:[101, 102, 99, 100]
        System.out.println(Arrays.toString(bytes));

        // 再继续读取文件
        len = fis.read(bytes);
        // 已经读到文件末尾,返回 -1
        System.out.println(len);
        // 输出结果:[101, 102, 99, 100]
        System.out.println(Arrays.toString(bytes));

        // 关闭流
        fis.close();

    }
}
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * FileOutPutStream 流以字节为单位把数据保存到文件中
 */
public class Test04 {
    public static void main(String[] args) throws IOException {
        // 调用构造方法指定要写入的文件,如果文件不存则会创建该文件
        // 以覆盖的形式写入文件
//        FileOutputStream fos = new FileOutputStream("/Users/Desktop/test");

        // 以追加的形式写入文件
        FileOutputStream fos = new FileOutputStream("/Users/Desktop/test", true);

        // 调用 write(int) 方法,一次写入一个字节
        fos.write(97);
        fos.write(98);
        fos.write(99);

        // 调用 write(byte[] b) 方法,把一个字节数组的所有字节写入文件
        byte [] bytes = "hello FileOutPutStream".getBytes();
        fos.write(bytes);

        // 调用 write(byte[] b, int off, int len) 方法,把一个字节的部分字节写入文件
        fos.write(bytes, 0, 5);

        // 关闭流
        fos.close();
    }
}

文件内容:

abchello FileOutPutStreamhello

BufferedInputStreamBufferedOutputStream

BufferedInputStream 缓冲输入字节流,字节流有一个8192字节的数组作为缓冲区,程序从缓冲区读取数据,不直接操作文件

BufferedOutputStream 缓冲输出字节流,程序把数据写入缓冲区,再由其他字节流从缓冲区把数据写入文件

BufferedInputStreamBufferedOutputStream 属于处理流

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * BufferedInputStream 流读取文件
 */
public class Test01 {
    public static void main(String[] args) throws IOException {
        m1();
    }

    public static void m1 () throws IOException {
        // 先创建字节流,文件内容:hello
        FileInputStream fis = new FileInputStream("/Users/Desktop/test");

        // 再创建缓冲流对字节流进行缓冲
        BufferedInputStream bis = new BufferedInputStream(fis);

        // 从缓冲区中读取文件
        int bb = bis.read();
        while (bb != -1) {
            System.out.println((char)bb);
            bb = bis.read();
        }

        // 关闭缓冲流
        bis.close();
    }
}

输出结果:

h
e
l
l
o
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * BufferedOutputStream 流写入文件
 */
public class Test02 {
    public static void main(String[] args) throws IOException {
        m2();
    }

    public static void m2 () throws IOException {
        // 先创建字节流
        FileOutputStream fos = new FileOutputStream("/Users/Desktop/test");

        // 再创建缓冲流
        BufferedOutputStream bos = new BufferedOutputStream(fos);

        // 把数据写入缓冲区
        bos.write(65);
        bos.write(66);
        bos.write(67);

        // 刷新缓冲区,把数据从缓冲区写入文件
        bos.flush();

        // 关闭缓冲流,直接关闭也会刷新缓冲区
        bos.close();
    }
}

文件内容:

ABC

DataInputStreamDataOutputStream

之前的 FileInputStream 流从文件中读取一组 01 二进制序列,在转换成相对应的数据,FileOutputStream 把相对应的数据转换成 01 二进制序列,再写入文件

DataInputStream 流可以直接中文件中读取整数,小数,字符,字符串,布尔类型类型的数据,DataOutputStream 可以直接把整数,小数,字符,字符串,布尔类型的数据写入文件

import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * DataOutputStream 流把带有格式的数据写入文件
 */
public class Test01 {
    public static void main(String[] args) throws IOException {
        // 先创建字节流
        FileOutputStream fos = new FileOutputStream("/Users/Desktop/test");

        // 在创建 DataOutputStream 流
        DataOutputStream dos = new DataOutputStream(fos);

        // 写入文件,写入的数据直接读入会显示乱码,需要使用 DataInputStream 流来读取
        dos.writeInt(123);
        dos.writeDouble(3.14);
        dos.writeChar('汉');
        dos.writeBoolean(false);
        dos.writeUTF("hello");

        // 关闭流
        dos.close();
    }
}
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * DataInputStream 读取数据
 */
public class Test02 {
    public static void main(String[] args) throws IOException {
        // 先创建字节流
        FileInputStream fis = new FileInputStream("/Users/Desktop/test");

        // 再创建 DataInputStream 流
        DataInputStream dis = new DataInputStream(fis);

        // 读取的顺序与写入的顺序需要保持一致
        int i = dis.readInt();
        double d = dis.readDouble();
        char c = dis.readChar();
        boolean b = dis.readBoolean();
        String s = dis.readUTF();

        // 关闭流
        dis.close();

        // 输出
        System.out.println(i);
        System.out.println(d);
        System.out.println(c);
        System.out.println(b);
        System.out.println(s);

    }
}

输出内容:

123
3.14
汉
false
hello

ObjectInputStreamObjectOutputStream

ObjectOutputStream 流把对象转换为二进制序列写入到文件,称为对象序列化

ObjectInputStream 流把读取到的二进制序列转换为对象,称为对象反序列化

对象序列化与反序列化的前提是对象的类要实现 Serializable 接口,这个接口是一个标志接口,没有抽象方法

import java.io.Serializable;

/**
 * 定义一个类
 */
public class Person implements Serializable {
    String name;
    int age;

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

/**
 * ObjectOutputStream 流把对象写入文件
 */
public class Test01 {
    public static void main(String[] args) throws IOException {
        Person p = new Person("张三", 18);

        // 创建字节流
        FileOutputStream fos = new FileOutputStream("/Users/Desktop/test");

        // 创建 ObjectOutputStream 流
        ObjectOutputStream oos = new ObjectOutputStream(fos);

        // 把对象写入文件,写入文件之后,需要使用 ObjectInputStream 流读取
        oos.writeObject(p);

        // 关闭流
        oos.close();
    }
}
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

/**
 * ObjectInputStream 流读取对象
 */
public class Test02 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 创建字节流
        FileInputStream fis = new FileInputStream("/Users/Desktop/test");

        // 创建 ObjectInputStream 流
        ObjectInputStream ois = new ObjectInputStream(fis);

        // 读取对象
        Object o = ois.readObject();

        // 关闭流
        ois.close();

        // 输出
        System.out.println(o);

    }
}

输出内容:

Person{name='张三', age=18}

PrintStream

打印内容到文件

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;

/**
 * PrintStream 打印字节流
 */
public class Test01 {
    public static void main(String[] args) throws FileNotFoundException {
        // 创建字节流
        FileOutputStream fos = new FileOutputStream("/Users/Desktop/test");
        // 创建打印流
        PrintStream ps = new PrintStream(fos);

        // 打印字节流常用的方法,print() 和 println(),打印信息到文件中
        ps.print("打印完不换行");
        ps.println("打印完换行");

        // 设置 system.out.println 方法,通过打印流打印到文件中
        System.setOut(ps);
        System.out.println("现在打印的内容不显示在屏幕上,而是打印到 test 文件中");

        // 把异常信息打印到文件中
        try {
            FileInputStream fis = new FileInputStream("不存在的文件");
        }catch (FileNotFoundException e) {
            // 把异常信息打印到 test 文件中
            e.printStackTrace(ps);
        }

        // 关闭流
        ps.close();

    }
}

文件内容:

打印完不换行打印完换行
现在打印的内容不显示在屏幕上,而是打印到 test 文件中
java.io.FileNotFoundException: 不存在的文件 (No such file or directory)
    at java.base/java.io.FileInputStream.open0(Native Method)
    at java.base/java.io.FileInputStream.open(FileInputStream.java:219)
    at java.base/java.io.FileInputStream.<init>(FileInputStream.java:157)
    at java.base/java.io.FileInputStream.<init>(FileInputStream.java:112)
    at printio.Test01.main(Test01.java:28)

FileReaderFileWriter

IO 流类中以 Reader 和 Writer 结尾的是字符流,用于读写只有字符的纯文本文件

FileReaderFileWriter 只能读写与当前环境编码兼容的文件

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
 * FileReader 和 FileWriter
 */
public class Test01 {
    public static void main(String[] args) throws IOException {
        readChar();
        readChar2();
        writeChar();

    }

    // 读取字符文件
    public static void readChar () throws IOException {
        // 创建字符流
        FileReader fr = new FileReader("/Users/Desktop/test");
        // 调用 read() 方法读取一个字符,返回读到的字符的码值,如果读到末尾返回 -1
        int code = fr.read();
        while (code != -1) {
            System.out.print((char)code);
            code = fr.read();
        }
        // 关闭流
        fr.close();
    }

    // 读取若干字符保存到字符数组
    public static void readChar2 () throws IOException {
        // 创建字符流
        FileReader fr = new FileReader("/Users/Desktop/test");
        // 定义一个数组
        char [] chars = new char[1024];
        // 读取若干字符存储到字符数组 chars 中,返回读到的字节数
        int len = fr.read(chars);
        while (len != -1) {
            System.out.print(String.valueOf(chars, 0, len));
            len = fr.read(chars);
        }
        // 关闭流
        fr.close();
    }

    // 写入字符文件
    public static void writeChar () throws IOException {
        // 创建字符流
        FileWriter fw = new FileWriter("/Users/Desktop/test");

        // 写入字符文件
        // 一次写入一个字符
        fw.write('1');
        fw.write('a');
        fw.write('汉');
        fw.write('#');

        // 写入字符数组
        char [] chars = "hello charArray".toCharArray();
        fw.write(chars);
        
        // 写入字符串
        fw.write("hello str")

        // 关闭流
        fw.close();

    }
}

InputStreamReaderOutputStreamWriter

如果想要读写编码不一致的文本文件,可以使用 InputStreamReaderOutputStreamWriter

InputStreamReader 可以把字节流转换为字符流

OutputStreamWriter 可以把字符流转换为字节流

import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.IOException;

/**
 * InputStreamReader 和 OutputStreamWriter
 */
public class Test02 {
    public static void main(String[] args) throws IOException {
        readGBKFile();
        writeGBKFile();
    }

    // 在 UTF8 环境读取 GBK 文件
    public static void readGBKFile () throws IOException {
        // 创建字节流
        FileInputStream fis = new FileInputStream("/Users/Desktop/test");
        // 创建转换流,把字节流以 GBK 格式转换为字符流
        InputStreamReader isr = new InputStreamReader(fis, "GBK");
        // 读取文件内容,返回的是字符对应的码值
        int code = isr.read();
        while (code != -1) {
            System.out.print((char)code);
            code = isr.read();
        }
        // 关闭流
        isr.close();
    }

    // 在 UTF8 环境下写入 GBK 文件
    public static void writeGBKFile () throws IOException {
        // 创建字节流
        FileOutputStream fos = new FileOutputStream("/Users/Desktop/test");
        // 创建转换流,把字符流以 GBK 格式转换为字节流
        OutputStreamWriter osw = new OutputStreamWriter(fos);
        // 写入文件
        osw.write("当前是 UTF8 编码环境,写入文件的编码是 GBK");
        // 关闭流
        osw.close();
    }
}

BufferedReaderBufferedWriter

BufferedWriter 可以对输出字符流进行缓冲,写入数据到缓冲区,刷新缓冲区,或者缓冲区已满,或者关闭流时,将缓冲区的数据写入文件

BufferedReader 可以对输入字符流进行缓冲,从缓冲区读取数据,不直接操作文件

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

/**
 * BufferedReader 和 BufferedWriter
 */
public class Test03 {
    public static void main(String[] args) throws IOException {
        writerBf();
        readBf();
    }

    // 使用字符缓冲流写入文件
    public static void writerBf () throws IOException {
        // 创建字符流
        FileWriter fw = new FileWriter("/Users/Desktop/test");
        // 创建缓冲字符流
        BufferedWriter bw = new BufferedWriter(fw);
        // 写入数据到缓冲区
        bw.write("写入到缓冲区");
        // 刷新缓冲区,把数据从缓冲区写入到文件
        bw.flush();
        // 关闭流
        bw.close();
    }

    // 使用字符缓冲流读取文件
    public static void readBf () throws IOException {
        // 创建字符流
        FileReader fr = new FileReader("/Users/Desktop/test");
        // 创建缓冲字符流
        BufferedReader br = new BufferedReader(fr);
        // 从缓冲区读取一行文件,如果读到文件末尾返回 null
        String line = br.readLine();
        while (line != null) {
            System.out.println(line);
            line = br.readLine();
        }
        // 关闭流
        br.close();
    }
}

输出结果:

写入到缓冲区
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,548评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,497评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,990评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,618评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,618评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,246评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,819评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,725评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,268评论 1 320
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,356评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,488评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,181评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,862评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,331评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,445评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,897评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,500评论 2 359