E IO流.java

前言:I/O(输入 / 输出)操作是构建各类应用程序的基石之一。Java 提供了功能强大且灵活的 I/O 流机制,用于处理数据的读取与写入,无论是简单的文本文件操作,还是复杂的网络数据传输,都离不开 I/O 流的支持。 

目录

一、初识 Java I/O 流

数据的 “传送带”

二、字节流操作

从读取到写入的实战

1. 读取文件(字节流)

2. 写入文件(字节流)

三、字符流操作

读写文本文件的简便之道

1. 读取文件(字符流)

2. 写入文件(字符流)

四、缓冲流

给 I/O 操作插上 “翅膀”

1. 字节缓冲流

2. 字符缓冲流

五、对象序列化

让对象 “穿越时空”

六、Java NIO

给 I/O 操作装上 “涡轮增压”

1. 通道(Channel)和缓冲区(Buffer)

2. 多路复用器(Selector)

总结


一、初识 Java I/O 流

数据的 “传送带”

I/O 流,说白了就是数据的 “传送带”,负责把数据从一个地方运到另一个地方。在 Java 里,它主要分为两类:字节流和字符流。

  • 字节流 :就像搬砖,一块砖一块砖地搬,适用于处理二进制数据,比如图片、音乐文件啥的。它的顶级老大是 InputStreamOutputStream

  • 字符流 :类似于搬书,一本一本搬,主要用于处理文本文件,毕竟读文本嘛,还是以字符为单位方便。它的顶级班头是 ReaderWriter

二、字节流操作

从读取到写入的实战

1. 读取文件(字节流)

先来个简单的,用 FileInputStream 读取文件内容。啥文件呢?就叫 “猫猫日记.txt” 吧,说不定里面记载了啥好玩的事儿呢。

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

public class CatDiaryReader {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            // 创建 FileInputStream 对象,去 “偷看” 猫猫日记
            fis = new FileInputStream("猫猫日记.txt");
            int data;
            // 开始读取猫猫日记啦,看看里面写啥了
            while ((data = fis.read()) != -1) {
                System.out.print((char) data);
            }
        } catch (IOException e) {
            System.out.println("读取猫猫日记出错了,呜呜呜!");
            e.printStackTrace();
        } finally {
            // 读完了记得关门,不然猫猫会生气的
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    System.out.println("关闭日记本失败,猫猫要抓我了!");
                    e.printStackTrace();
                }
            }
        }
    }
}

这段代码就像在偷偷翻看猫猫的日记本,把里面的内容一字一句读出来。要是读成功了,就能看到猫猫的小心思;要是出错了,就只能哭着喊 “呜呜呜” 了。

2. 写入文件(字节流)

再试试用 FileOutputStream 给猫猫写日记。说不定哪天猫猫看了会感动呢。

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

public class CatDiaryWriter {
    public static void main(String[] args) {
        FileOutputStream fos = null;
        try {
            // 创建 FileOutputStream 对象,给猫猫写日记
            fos = new FileOutputStream("猫猫日记.txt");
            String content = "今天我抓了好多老鼠,真是太开心啦!";
            byte[] bytes = content.getBytes(); // 把文字变成字节君
            // 把字节君写入猫猫日记本
            fos.write(bytes);
            System.out.println("猫猫日记写成功啦!");
        } catch (IOException e) {
            System.out.println("给猫猫写日记失败,猫猫要饿肚子啦!");
            e.printStackTrace();
        } finally {
            // 写完了也要关门,不然字会跑掉的
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    System.out.println("关闭日记本失败,字要跑光啦!");
                    e.printStackTrace();
                }
            }
        }
    }
}

写着写着,感觉猫猫的生活都变得丰富多彩了呢。

三、字符流操作

读写文本文件的简便之道

1. 读取文件(字符流)

FileReader 去读取另一个文件,这次是 “狗狗冒险记.txt”,看看狗狗的惊险刺激之旅。

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

public class DogAdventureReader {
    public static void main(String[] args) {
        FileReader fr = null;
        try {
            // 创建 FileReader 对象,去读狗狗冒险记
            fr = new FileReader("狗狗冒险记.txt");
            char[] buffer = new char[1024]; // 创建一个字符缓冲区
            int length;
            // 开始读取啦,看看狗狗都经历了啥
            while ((length = fr.read(buffer)) != -1) {
                System.out.print(new String(buffer, 0, length));
            }
        } catch (IOException e) {
            System.out.println("读取狗狗冒险记出错了,狗狗要惨啦!");
            e.printStackTrace();
        } finally {
            // 读完记得把书合上
            if (fr != null) {
                try {
                    fr.close();
                } catch (IOException e) {
                    System.out.println("关闭书本失败,狗狗的故事要散架啦!");
                    e.printStackTrace();
                }
            }
        }
    }
}

这就像在翻阅一本精彩的冒险故事书,一页页地读,把狗狗的刺激经历都展现在眼前。

2. 写入文件(字符流)

FileWriter 给狗狗写冒险故事,让它的生活更加有戏。

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

public class DogAdventureWriter {
    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            // 创建 FileWriter 对象,给狗狗写冒险故事
            fw = new FileWriter("狗狗冒险记.txt");
            String content = "今天我追了一只蝴蝶,跑遍了整个院子,太好玩啦!";
            // 把故事写进狗狗的冒险记
            fw.write(content);
            System.out.println("狗狗冒险记写成功啦!");
        } catch (IOException e) {
            System.out.println("给狗狗写冒险记失败,狗狗要无聊死啦!");
            e.printStackTrace();
        } finally {
            // 写完记得把笔放下,不然墨水会干掉的
            if (fw != null) {
                try {
                    fw.close();
                } catch (IOException e) {
                    System.out.println("放下笔失败,墨水要洒啦!");
                    e.printStackTrace();
                }
            }
        }
    }
}

写着写着,狗狗的生活都变得有声有色了。

四、缓冲流

给 I/O 操作插上 “翅膀”

1. 字节缓冲流

  • BufferedInputStream :就像给读取数据的路途加了个 “超级加油站”,让数据传输更快。

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

public class FastCatDiaryReader {
    public static void main(String[] args) {
        BufferedInputStream bis = null;
        try {
            // 创建 FileInputStream 对象
            FileInputStream fis = new FileInputStream("猫猫日记.txt");
            // 把 FileInputStream 变成带缓冲的,速度飞起来
            bis = new BufferedInputStream(fis);
            int data;
            while ((data = bis.read()) != -1) {
                System.out.print((char) data);
            }
        } catch (IOException e) {
            System.out.println("快速读取猫猫日记失败,速度还是不够快!");
            e.printStackTrace();
        } finally {
            // 跑完记得停下来,不然会摔倒的
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    System.out.println("停止失败,还在原地打转转!");
                    e.printStackTrace();
                }
            }
        }
    }
}
  • BufferedOutputStream :给写入数据的通道装了个 “超级滑梯”,让写入速度飞起来。

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FastCatDiaryWriter {
    public static void main(String[] args) {
        BufferedOutputStream bos = null;
        try {
            // 创建 FileOutputStream 对象
            FileOutputStream fos = new FileOutputStream("猫猫日记.txt");
            // 把 FileOutputStream 变成带缓冲的,飞速写入
            bos = new BufferedOutputStream(fos);
            String content = "今天我在阳光下打了个盹,梦到了好多好吃的鱼!";
            byte[] bytes = content.getBytes();
            bos.write(bytes);
            bos.flush(); // 把缓冲区的数据都推出去,别留着啦
            System.out.println("快速写入猫猫日记成功啦!");
        } catch (IOException e) {
            System.out.println("快速写入猫猫日记失败,滑梯卡住了!");
            e.printStackTrace();
        } finally {
            // 玩完滑梯要下来,不然会摔跤的
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    System.out.println("从滑梯下来失败,还在上面摇摇晃晃!");
                    e.printStackTrace();
                }
            }
        }
    }
}

2. 字符缓冲流

  • BufferedReader :就像给读取文本的路途装了个 “超级传送门”,让读取效率倍增。

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

public class FastDogAdventureReader {
    public static void main(String[] args) {
        BufferedReader br = null;
        try {
            // 创建 FileReader 对象
            FileReader fr = new FileReader("狗狗冒险记.txt");
            // 把 FileReader 变成带缓冲的,飞速读取
            br = new BufferedReader(fr);
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("快速读取狗狗冒险记失败,传送门故障!");
            e.printStackTrace();
        } finally {
            // 穿过传送门后要出来,不然会迷路的
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    System.out.println("传送门出口打不开,还在里面转圈圈!");
                    e.printStackTrace();
                }
            }
        }
    }
}
  • BufferedWriter :给写入文本的通道安了个 “超级喷气背包”,让写入速度飞起来。

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

public class FastDogAdventureWriter {
    public static void main(String[] args) {
        BufferedWriter bw = null;
        try {
            // 创建 FileWriter 对象
            FileWriter fw = new FileWriter("狗狗冒险记.txt");
            // 把 FileWriter 变成带缓冲的,飞速写入
            bw = new BufferedWriter(fw);
            String content = "今天我挖了一个大大的坑,打算明天在里面埋个宝藏!\n挖坑好累啊,但是很有趣。";
            bw.write(content);
            bw.newLine(); // 换行,就像在纸上换一行写
            bw.write("期待明天的宝藏埋藏之旅!");
            bw.flush(); // 把喷气背包里的余气都喷完,确保文字都落下来
            System.out.println("快速写入狗狗冒险记成功啦!");
        } catch (IOException e) {
            System.out.println("快速写入狗狗冒险记失败,喷气背包没燃料啦!");
            e.printStackTrace();
        } finally {
            // 飞完记得降落,不然会掉下来
            if (bw != null) {
                try {
                    bw.close();
                } catch (IOException e) {
                    System.out.println("降落失败,还在天上飘着呢!");
                    e.printStackTrace();
                }
            }
        }
    }
}

五、对象序列化

让对象 “穿越时空”

对象序列化就是把 Java 对象变成字节序列,让它可以被存储或者传输。就像给对象施了个 “魔法咒语”,让它能穿越到别的地方。要实现这个魔法,类得实现 Serializable 接口。

import java.io.*;

class Cat implements Serializable {
    private static final long serialVersionUID = 1L; // 这是序列化的版本号,很重要哦
    private String name;
    private int age;

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

    @Override
    public String toString() {
        return "Cat{name='" + name + "', age=" + age + "}";
    }
}

public class CatSerialization {
    public static void main(String[] args) {
        Cat cat = new Cat("咪咪", 3);

        // 把猫猫对象序列化,就像把猫猫装进魔法瓶子里
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("猫猫魔法瓶.ser"))) {
            oos.writeObject(cat);
            System.out.println("猫猫被成功装进魔法瓶!");
        } catch (IOException e) {
            System.out.println("装猫猫进魔法瓶失败,魔法失效啦!");
            e.printStackTrace();
        }

        // 把猫猫对象从魔法瓶子里变出来
        Cat magicCat = null;
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("猫猫魔法瓶.ser"))) {
            magicCat = (Cat) ois.readObject();
            System.out.println("猫猫从魔法瓶里成功变出来啦!");
            System.out.println(magicCat);
        } catch (IOException | ClassNotFoundException e) {
            System.out.println("从魔法瓶变猫猫失败,可能是瓶子碎了!");
            e.printStackTrace();
        }
    }
}

六、Java NIO

给 I/O 操作装上 “涡轮增压”

Java NIO 提供了一种更高效、更高级的 I/O 操作方式,就像给 I/O 流装上了 “涡轮增压”。

1. 通道(Channel)和缓冲区(Buffer)

通道就是数据传输的 “高速公路”,缓冲区是放数据的 “集装箱”。

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class DogStoryNIOReader {
    public static void main(String[] args) {
        try (FileChannel fileChannel = FileChannel.open(Paths.get("狗狗冒险记.txt"), StandardOpenOption.READ)) {
            ByteBuffer buffer = ByteBuffer.allocate(1024); // 创建一个集装箱
            while (fileChannel.read(buffer) != -1) { // 把数据从通道读到集装箱
                buffer.flip(); // 把集装箱翻过来,准备倒数据
                while (buffer.hasRemaining()) { // 只要还有数据,就倒出来
                    System.out.print((char) buffer.get());
                }
                buffer.clear(); // 倒完数据,清空集装箱
            }
        } catch (IOException e) {
            System.out.println("用 NIO 读取狗狗冒险记失败,高速公路堵车啦!");
            e.printStackTrace();
        }
    }
}

2. 多路复用器(Selector)

多路复用器就像是个 “超级交通警察”,能同时管理多个通道。

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.Selector;

public class NIOServer {
    public static void main(String[] args) {
        try {
            // 创建 ServerSocketChannel
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.bind(new InetSocketAddress(8080)); // 绑定端口 8080
            serverSocketChannel.configureBlocking(false); // 设置为非阻塞模式,就像开启了自动刹车系统

            // 创建超级交通警察(Selector)
            Selector selector = Selector.open();
            // 把 ServerSocketChannel 注册到超级交通警察那,让它监听接受连接事件
            serverSocketChannel.register(selector, ServerSocketChannel.validOps());

            while (true) {
                // 超级交通警察开始工作,等待有通道准备好
                selector.select();
                // 获取已经被处理好的事件
                selector.selectedKeys().forEach(key -> {
                    try {
                        if (key.isAcceptable()) {
                            // 接受新的连接请求
                            SocketChannel socketChannel = serverSocketChannel.accept();
                            socketChannel.configureBlocking(false);
                            System.out.println("有新的客户端来连接啦,IP 是:" + socketChannel.getRemoteAddress());
                        }
                    } catch (IOException e) {
                        System.out.println("处理客户端连接失败,网络信号不好!");
                        e.printStackTrace();
                    }
                });
                // 处理完一个事件,就把这个事件从列表里移除
                selector.selectedKeys().clear();
            }
        } catch (IOException e) {
            System.out.println("启动超级交通警察失败,交通瘫痪啦!");
            e.printStackTrace();
        }
    }
}

总结

本文深入浅出地讲解了Java I/O流的知识,从基础的字节流、字符流操作,到提升效率的缓冲流,再到便捷的对象序列化,以及高效的Java NIO技术,逐步深入。通过生动的代码示例和调皮的注释,将晦涩的概念通俗化,助力新手轻松掌握Java I/O流的实用性与趣味性,为大家在编程路上攻克Java I/O流提供了有力支持。

你可能感兴趣的:(26字母学习:java入门篇,java,开发语言,学习方法,visual,studio,code,后端)