万字长文+思维导图帮你梳理 Java IO 流,还学不会你来打我(值得收藏)(下)

简介: 万字长文+思维导图帮你梳理 Java IO 流,还学不会你来打我(值得收藏)(下)

字符缓冲流


对字符节点流的装饰,下面是字符缓冲流的构造方法


public BufferedReader(Reader in) {
 // private static int defaultCharBufferSize = 8192;
 // 内部维护了一个字符数组
    // private char cb[];
    this(in, defaultCharBufferSize);
}
public BufferedWriter(Writer out) {
        this(out, defaultCharBufferSize);
}


字符缓冲流的特有方法


方法名 方法说明
BufferedReader String readLine() throws IOException 一行行读取,读取到最后一行返回null
BufferedWriter void newLine() throws IOException 写一个换行符到文件中,实现换行


// 创建流对象
BufferedReader br = new BufferedReader(new FileReader("D:/三国/赵云.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("D:/三国/赵子龙.txt"));
String line = null;
while ((line = br.readLine())!=null) {
  System.out.println(line);
  bw.write(line);
  bw.newLine();
}
// 结果
我乃常山赵子龙
于万军从中,取上将首级


缓冲流的正确姿势


缓冲流是IO流中最重要的知识点,下面通过代码实现正确用IO流的姿势


BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
    bis = new BufferedInputStream(new FileInputStream(new File("D:/三国/视频.mp4")));
    bos = new BufferedOutputStream(new FileOutputStream(new File("D:/三国/拷贝.mp4")));
    int len;
    // 一次传输8M的文件,实际测试这里传输的大小并不影响传输的速度
    byte[] data = new byte[8 * 1024];
    while ((len = bis.read(data)) != -1) {
        bos.write(data, 0, len);
    }
} catch (IOException e) {
    log.error("error", e);
} finally {
   // finally块中关闭流,确保资源一定被关闭
    if (bis != null) {
        try {
            bis.close();
        } catch (IOException e) {
            log.error("error", e);
        }
    }
    if (bos != null) {
        try {
            bos.close();
        } catch (IOException e) {
            log.error("error", e);
        }
    }
}

转换流

字符编码与字符集


字符编码


计算机存储的数据都是二进制的,而我们在电脑上看到的数字、英文、汉字等都是二进制转换的结果


  • 将字符转换成二进制,为编码


  • 将二进制转换为字符,为解码


字符编码 就是 自然语言和二进制的对应规则


字符集


就是一个编码表,常见的字符集有ASCII字符集、GBK字符集、Unicode字符集等,具体各个编码的介绍在这里就不介绍了。


image.png


IDEA中,使用 FileReader 读取项目中的文本文件。IDEA可以设置为GBK 编码,当读取Windows系统中创建的默认的UTF8文本文件时,就会出现乱码 。


如下例


image.png


idea的字符集设置 默认是UTF-8,这里修改为GBK


image.png


运行的代码及结果


FileReader fileReader = new FileReader("D:/sanguo/utf8.txt");
int read;
while ((read = fileReader.read()) != -1) {
    System.out.print((char)read);
}
// 浣犲ソ


InputStreamReader


Reader的子类,读取字节,并使用指定的字符集将其解码为字符。字符集可以自己指定,也可以使用平台的默认字符集。


构造方法如下


// 使用平台默认字符集
public InputStreamReader(InputStream in) {}
// 指定字符集
public InputStreamReader(InputStream in, String charsetName)
        throws UnsupportedEncodingException{}


读取文件的“你好",文件默认的字符集是UTF8


// 创建流对象,默认UTF8编码
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:/三国/utf8.txt"));
// 创建流对象,指定GBK编码
InputStreamReader isr2 = new InputStreamReader(new FileInputStream("D:/三国/utf8.txt"), "GBK");
int read;
while ((read = isr.read()) != -1) {
    System.out.println((char) read);
}
while ((read = isr2.read()) != -1) {
    System.out.println((char) read);
}
// 输出结果
你好
浣犲ソ


OutputStreamWriter


Writer的子类,使用指定的字符集将字符编码为字节。字符集可以自己指定,也可以使用平台的默认字符集。


构造方法如下


// 使用平台默认字符集
public OutputStreamWriter(OutputStream out) {}
// 使用平台默认字符集
public OutputStreamWriter(OutputStream out, String charsetName)
throws UnsupportedEncodingException{}


如下面的代码,将你好写入文件。写入后两个文件的字符集不一样,文件大小也不同


// 创建流对象,默认UTF8编码
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:/三国/黄忠.txt"));
osw.write("你好"); // 保存为6个字节
// 创建流对象,指定GBK编码
OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream("D:/三国/马超.txt"),"GBK");
osw2.write("你好");// 保存为4个字节


image.png


对象流

序列化


jdk提供了对象序列化的方式,该序列化机制将对象转为二进制流,二进制流主要包括对象的数据、对象的类型、对象的属性。可以将java对象转为二进制流写入文件中。文件会持久保存了对象的信息。


同理,从文件中读出对象的信息为反序列化的过程


对象想序列化,满足的条件:


  1. 该类必须实现 java.io.Serializable 接口, Serializable 是一个标记接口(没有任何抽象方法),不实现此接口的类将不会使任何状态序列化或反序列化,会抛出 NotSerializableException 。


  1. 该类的所有属性必须是可序列化的,如果有一个属性不需要可序列化的,则该属性使用transient 关键字修饰


ObjectOutputStream


该类实现将对象序列化后写出到外部设备,如硬盘文件


public ObjectOutputStream(OutputStream out) throws IOException{}


常用方法


方法名 方法说明
void writeObject(Object obj) throws IOException 将指定的对象写出



如下代码,将User对象写入文件中


public class User implements Serializable {
    private static final long serialVersionUID = 8289102797441171947L;
    private String name;
    private Integer age;
}
// 下面是将对象输出到文件的核心代码
User user = new User("马超",20);
// 创建序列化流对象
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("D:/三国/马超.txt"));
// 写出对象
out.writeObject(user);


注意:


  1. 实现了Serializable的实体一定要加一个serialVersionUID变量,这也是习惯问题,idea可以设置一下。


  1. serialVersionUID生成后不要改变,避免反序列化失败,改变后会抛出InvalidClassException异常


image.png


生成的文件内容如下


image.png


ObjectInputStream


该类将ObjectOutputStream写出的对象反序列化成java对象


public ObjectInputStream(InputStream in) throws IOException


常用方法


方法名 方法说明
Object readObject()     throws IOException, ClassNotFoundException 读取对象



ObjectInputStream in = new ObjectInputStream(new FileInputStream("D:/三国/马超.txt"));
// 强转为user
User user = (User) in.readObject();
System.out.println(user);
// 输出内容
User(name=马超, age=20)


对象和字节数组的转换


利用对象流和字节数组流结合 ,可以实现java对象和byte[]之间的互转


// 将对象转为byte[]
public static <T> byte[] t1(T t) {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(bos);
    oos.writeObject(t);
    return bos.toByteArray();
}
// 将byte[]转为对象
public static <T> T t2(byte[] data) throws IOException, ClassNotFoundException {
    ByteArrayInputStream bos = new ByteArrayInputStream(data);
    ObjectInputStream oos = new ObjectInputStream(bos);
    return (T) oos.readObject();
}

管道流(了解)

管道流主要用于两个线程间的通信,即一个线程通过管道流给另一个线程发数据


注意:线程的通信一般使用wait()/notify(),使用流也可以达到通信的效果,并且可以传递数据


使用的类是如下


  • PipedInputStream和PipedOutStream


  • PipedReader和PipedWriter


这里使用字节流为例


class Sender implements Runnable {
    private PipedOutputStream pos;
    private String msg;
    public Sender(String msg) {
        this.pos = new PipedOutputStream();
        this.msg = msg;
    }
    @Override
    public void run() {
       pos.write(msg.getBytes());
    }
    public PipedOutputStream getPos() {
        return pos;
    }
}
class Receiver implements Runnable {
    private PipedInputStream pis;
    public Receiver() {
        this.pis = new PipedInputStream();
    }
    @Override
    public void run() {
         byte[] data = new byte[1024];
            int len;
            while ((len = pis.read(data)) != -1) {
                System.out.println(new String(data, 0, len));
            }
    }
}
Sender sender = new Sender("hello");
Receiver receiver = new Receiver();
receiver.getPis().connect(sender.getPos());
new Thread(sender).start();
new Thread(receiver).start();
// 控制台输出  hello

输入与输出流(了解)

System.in和System.out代表了系统标准的输入、输出设备


默认输入设备是键盘,默认输出设备是控制台


可以使用System类的setIn,setOut方法对默认设备进行改变


我们开发中经常使用的输出到控制台上的内容的方法。


System.out.println("a");
System.out.print("b");
class System{
    public final static InputStream in = null;
    public final static PrintStream out = null;
}
public PrintStream(String fileName) throws FileNotFoundException{}

数据流(了解)

主要方便读取Java基本类型以及String的数据,有DataInputStream 和 DataOutputStream两个实现类


DataOutputStream dos = new DataOutputStream(new FileOutputStream("D:/三国/周瑜.txt"));
dos.writeUTF("周瑜");
dos.writeBoolean(false);
dos.writeLong(1234567890L);
DataInputStream dis = new DataInputStream(new FileInputStream("D:/三国/周瑜.txt"));
String s = dis.readUTF();
System.out.println(s);
boolean b = dis.readBoolean();
System.out.println(b);
// 输出
周瑜
false


IO流总结


以上各个章节详细介绍了各个流,可见流的种类比较多,记忆确实增加了困难。但是可以通过思维导图的方式整理出来,方便记忆。


字节流的导图


image.png


字符流的导图


image.png


按照功能划分


image.png


输入、输出对应关系


image.png


结语


短期的加更计划


  1. NIO


  1. tomcat系列源码解析


文章篇幅较长,给看到这里的小伙伴点个大大的赞!由于作者水平有限,文章中难免会有错误之处,欢迎小伙伴们反馈指正。


如果觉得文章对你有帮助,麻烦 点赞、评论、转发、在看 、关注 走起

你的支持是我加更最大的动力!!!


相关文章
|
25天前
|
人工智能 JavaScript 安全
【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
86 13
【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
|
10天前
|
缓存 网络协议 Java
JAVA网络IO之NIO/BIO
本文介绍了Java网络编程的基础与历史演进,重点阐述了IO和Socket的概念。Java的IO分为设备和接口两部分,通过流、字节、字符等方式实现与外部的交互。
|
4月前
|
Java
java 中 IO 流
Java中的IO流是用于处理输入输出操作的机制,主要包括字节流和字符流两大类。字节流以8位字节为单位处理数据,如FileInputStream和FileOutputStream;字符流以16位Unicode字符为单位,如FileReader和FileWriter。这些流提供了读写文件、网络传输等基本功能。
73 10
|
5月前
|
存储 缓存 Java
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
这篇文章详细介绍了Java中的IO流,包括字符与字节的概念、编码格式、File类的使用、IO流的分类和原理,以及通过代码示例展示了各种流的应用,如节点流、处理流、缓存流、转换流、对象流和随机访问文件流。同时,还探讨了IDEA中设置项目编码格式的方法,以及如何处理序列化和反序列化问题。
145 1
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
|
6月前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
|
5月前
|
Java 数据处理 开发者
揭秘Java IO流:字节流与字符流的神秘面纱!
揭秘Java IO流:字节流与字符流的神秘面纱!
69 1
|
5月前
|
自然语言处理 Java 数据处理
Java IO流全解析:字节流和字符流的区别与联系!
Java IO流全解析:字节流和字符流的区别与联系!
169 1
|
6月前
|
Java 大数据 API
Java 流(Stream)、文件(File)和IO的区别
Java中的流(Stream)、文件(File)和输入/输出(I/O)是处理数据的关键概念。`File`类用于基本文件操作,如创建、删除和检查文件;流则提供了数据读写的抽象机制,适用于文件、内存和网络等多种数据源;I/O涵盖更广泛的输入输出操作,包括文件I/O、网络通信等,并支持异常处理和缓冲等功能。实际开发中,这三者常结合使用,以实现高效的数据处理。例如,`File`用于管理文件路径,`Stream`用于读写数据,I/O则处理复杂的输入输出需求。
339 12
|
5月前
|
Java
Java 中 IO 流的分类详解
【10月更文挑战第10天】不同类型的 IO 流具有不同的特点和适用场景,我们可以根据具体的需求选择合适的流来进行数据的输入和输出操作。在实际应用中,还可以通过组合使用多种流来实现更复杂的功能。
97 0
|
5月前
|
存储 Java 程序员
【Java】文件IO
【Java】文件IO
57 0