墨风如雪博客

  • 源码小店
  • 导航站
  • 登录
  • java
  • 资源分享
让AI使用变得如此简单
  1. 首页
  2. java
  3. 正文

探究Java IO流内部工作原理

2023年 5月 28日 141点热度 0人点赞 0条评论

1. Java IO 流概述

什么是 Java IO 流

Java IO(Input/Output)流是 Java 中常用的一种输入/输出机制,包括字节流和字符流两种类型。Java IO 流提供了一种简单而又灵活的方式,让程序能够读取和写入各种类型的数据,如文件、网络数据等。

在 Java 中,所有的 IO 操作都是通过流来完成的,流是一种数据传输的方式,数据在流中按照一定的顺序传输,可以是单向的或双向的。

Java IO 流的分类

Java IO 流可以分为两种类型:字节流和字符流。字节流主要用于处理二进制数据,而字符流则主要用于处理文本数据。

字节流和字符流的区别在于处理的数据类型不同,字节流处理的是二进制数据,而字符流处理的是文本数据。此外,字符流还提供了一些高级功能,如自动编码和解码等。

2. Java 字节流

InputStream 和 OutputStream

InputStream 和 OutputStream 是 Java 中最基本的字节流类,分别用于读取和写入字节流数据。常用的子类包括 FileInputStream、FileOutputStream、ByteArrayInputStream、ByteArrayOutputStream 等。

InputStream 类和 OutputStream 类是 Java IO 中最基本的字节流类,它们分别提供了读取和写入字节流数据的功能。InputStream 类中最常用的方法是 read(),用于读取字节流数据,而 OutputStream 类中最常用的方法是 write(),用于写入字节流数据。

try (InputStream inputStream = new FileInputStream("example.txt")) {
    int data;
    while ((data = inputStream.read()) != -1) {
        System.out.print((char) data);
    }
} catch (IOException e) {
    e.printStackTrace();
}

BufferedInputStream 和 BufferedOutputStream

BufferedInputStream 和 BufferedOutputStream 是 InputStream 和 OutputStream 的缓冲流版本,可以提高读写效率。

BufferedInputStream 和 BufferedOutputStream 是对 InputStream 和 OutputStream 的包装类,通过在内存中建立缓冲区来减少对底层流的频繁访问,从而提高读写效率。在使用 BufferedInputStream 和 BufferedOutputStream 时,需要注意及时关闭流资源,否则可能会出现数据丢失或内存泄漏的问题。

try (InputStream inputStream = new BufferedInputStream(new FileInputStream("example.txt"));
     OutputStream outputStream = new BufferedOutputStream(new FileOutputStream("output.txt"))) {
    int data;
    while ((data = inputStream.read()) != -1) {
        outputStream.write(data);
    }
} catch (IOException e) {
    e.printStackTrace();
}

DataInputStream 和 DataOutputStream

DataInputStream 和 DataOutputStream 是字节流中的高级流,可以用于读写基本数据类型和字符串。

DataInputStream 和 DataOutputStream 提供了一种方便的方式,可以将基本数据类型和字符串写入到字节流中,也可以从字节流中读取基本数据类型和字符串。这些方法都是基于大端字节序(Big-Endian)的,可以通过重载方法来指定小端字节序(Little-Endian)。

try (DataOutputStream outputStream = new DataOutputStream(new FileOutputStream("data.bin"));
     DataInputStream inputStream = new DataInputStream(new FileInputStream("data.bin"))) {
    outputStream.writeInt(123);
    outputStream.writeDouble(3.14);
    outputStream.writeUTF("Hello, world!");

    int intValue = inputStream.readInt();
    double doubleValue = inputStream.readDouble();
    String stringValue = inputStream.readUTF();

    System.out.println(intValue);
    System.out.println(doubleValue);
    System.out.println(stringValue);
} catch (IOException e) {
    e.printStackTrace();
}

ObjectInputStream 和 ObjectOutputStream

ObjectInputStream 和 ObjectOutputStream 是字节流中的高级流,可以用于读写 Java 对象。

ObjectInputStream 和 ObjectOutputStream 可以用于将 Java 对象序列化为字节流,或将字节流反序列化为 Java 对象。这些方法需要实现 Serializable 接口,否则会抛出 NotSerializableException 异常。

public class User implements Serializable {
    private static final long serialVersionUID = 1L;

    private String name;
    private int age;

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

try (ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("user.bin"));
     ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("user.bin"))) {
    User user = new User("Tom", 20);
    outputStream.writeObject(user);

    User newUser = (User) inputStream.readObject();
    System.out.println(newUser.getName());
    System.out.println(newUser.getAge());
} catch (IOException | ClassNotFoundException e) {
    e.printStackTrace();
}

PipedInputStream 和 PipedOutputStream

PipedInputStream 和 PipedOutputStream 是字节流中的管道流,用于线程间进行数据传输。

PipedInputStream 和 PipedOutputStream 可以用于在线程间传输数据。PipedInputStream 从 PipedOutputStream 中读取数据,而 PipedOutputStream 将数据写入到 PipedInputStream 中。需要注意的是,PipedInputStream 和 PipedOutputStream 必须在不同的线程中使用,否则会出现死锁现象。

try (PipedOutputStream outputStream = new PipedOutputStream();
     PipedInputStream inputStream = new PipedInputStream(outputStream)) {
    new Thread(() -> {
        try {
            outputStream.write("Hello, world!".getBytes());
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }).start();

    int data;
    while ((data = inputStream.read()) != -1) {
        System.out.print((char) data);
    }
} catch (IOException e) {
    e.printStackTrace();
}

3. Java 字符流

Reader 和 Writer

Reader 和 Writer 是 Java 中最基本的字符流类,分别用于读取和写入字符流数据。常用的子类包括 FileReader、FileWriter、CharArrayReader、CharArrayWriter 等。

Reader 和 Writer 是 Java 中最基本的字符流类,它们分别提供了读取和写入字符流数据的功能。Reader 类中最常用的方法是 read(),用于读取字符流数据,而 Writer 类中最常用的方法是 write(),用于写入字符流数据。

try (Reader reader = new FileReader("example.txt")) {
    int data;
    while ((data = reader.read()) != -1) {
        System.out.print((char) data);
    }
} catch (IOException e) {
    e.printStackTrace();
}

BufferedReader 和 BufferedWriter

BufferedReader 和 BufferedWriter 是 Reader 和 Writer 的缓冲流版本,可以提高读写效率。

BufferedReader 和 BufferedWriter 是对 Reader 和 Writer 的包装类,通过在内存中建立缓冲区来减少对底层流的频繁访问,从而提高读写效率。在使用 BufferedReader 和 BufferedWriter 时,需要注意及时关闭流资源,否则可能会出现数据丢失或内存泄漏的问题。

try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"));
     BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))) {
    String line;
    while ((line = reader.readLine()) != null) {
        writer.write(line);
        writer.newLine();
    }
} catch (IOException e) {
    e.printStackTrace();
}

3. Java 字符流(续)

InputStreamReader 和 OutputStreamWriter

InputStreamReader 和 OutputStreamWriter 是字节流和字符流之间的转换流,可以将字节流转换成字符流,或将字符流转换成字节流。

InputStreamReader 和 OutputStreamWriter 可以用于将字节流转换成字符流,或将字符流转换成字节流。在使用 InputStreamReader 和 OutputStreamWriter 时,需要指定字符编码,否则可能会出现乱码的问题。

try (InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("example.txt"), StandardCharsets.UTF_8);
     OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("output.txt"), StandardCharsets.UTF_8)) {
    int data;
    while ((data = inputStreamReader.read()) != -1) {
        outputStreamWriter.write(data);
    }
} catch (IOException e) {
    e.printStackTrace();
}

CharArrayReader 和 CharArrayWriter

CharArrayReader 和 CharArrayWriter 是字符流中的内存流,可以将字符存储在内存中,而不是在文件中。

CharArrayReader 和 CharArrayWriter 是字符流中的内存流,可以将字符存储在内存中,而不是在文件中。CharArrayReader 从内存中读取字符,而 CharArrayWriter 将字符写入内存中。需要注意的是,CharArrayReader 和 CharArrayWriter 都是线程不安全的,如果需要在多线程中使用,需要进行同步。

try (CharArrayWriter writer = new CharArrayWriter()) {
    writer.write("Hello, world!");

    try (CharArrayReader reader = new CharArrayReader(writer.toCharArray())) {
        int data;
        while ((data = reader.read()) != -1) {
            System.out.print((char) data);
        }
    }
} catch (IOException e) {
    e.printStackTrace();
}

StringReader 和 StringWriter

StringReader 和 StringWriter 是字符流中的内存流,可以将字符存储在字符串中,而不是在文件中。

StringReader 和 StringWriter 是字符流中的内存流,可以将字符存储在字符串中,而不是在文件中。StringReader 从字符串中读取字符,而 StringWriter 将字符写入字符串中。

try (StringWriter writer = new StringWriter()) {
    writer.write("Hello, world!");

   try (StringReader reader = new StringReader(writer.toString())) {
        int data;
        while ((data = reader.read()) != -1) {
            System.out.print((char) data);
        }
    }
} catch (IOException e) {
    e.printStackTrace();
}

BufferedReader 和 BufferedWriter 结合使用

BufferedReader 和 BufferedWriter 可以结合使用,实现高效的文本文件读写操作。

BufferedReader 和 BufferedWriter 可以结合使用,实现高效的文本文件读写操作。BufferedReader 可以按行读取文本文件,而 BufferedWriter 可以按行写入文本文件。

try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"));
     BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))) {
    String line;
    while ((line = reader.readLine()) != null) {
        writer.write(line);
        writer.newLine();
    }
} catch (IOException e) {
    e.printStackTrace();
}

4. Java NIO

什么是 Java NIO

Java NIO(New IO)是 Java 中提供的一种新的 IO 机制,主要用于实现高性能、高并发的网络编程。Java NIO 提供了一种基于通道(Channel)和缓冲区(Buffer)的数据读写方式,相较于传统的 IO 流,具有更高的效率和灵活性。

Java NIO 的组成部分

Java NIO 的组成部分包括通道(Channel)、缓冲区(Buffer)、选择器(Selector)和文件锁(FileLock)等。

通道(Channel)是 Java NIO 中的核心组件,它代表着一个连接到文件、套接字或其他可读写资源的打开链接。缓冲区(Buffer)是用于存储数据的容器,可以使用缓冲区读取和写入数据。选择器(Selector)是 Java NIO 中的另一个重要组件,它可以用于监控多个通道的事件。文件锁(FileLock)是用于在多个进程或线程之间共享文件的一种机制。

通道(Channel)

通道(Channel)是 Java NIO 中的核心组件,它代表着一个连接到文件、套接字或其他可读写资源的打开链接。

Java NIO 中的通道(Channel)类似于传统 IO 中的流(Stream),但有两个主要的区别:

  • 通道可以进行读取和写入操作,而流只能进行单向操作;
  • 通道可以实现异步读写,而流只能进行阻塞式读写。

Java NIO 中的通道包括 FileChannel、SocketChannel、ServerSocketChannel 和 DatagramChannel 等。

try (FileChannel channel = FileChannel.open(Paths.get("example.txt"), StandardOpenOption.READ)) {
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    int bytesRead = channel.read(buffer);
    while (bytesRead != -1) {
        buffer.flip();
        while (buffer.hasRemaining()) {
            System.out.print((char) buffer.get());
        }
        buffer.clear();
        bytesRead = channel.read(buffer);
    }
} catch (IOException e) {
    e.printStackTrace();
}

缓冲区(Buffer)

缓冲区(Buffer)是用于存储数据的容器,可以使用缓冲区读取和写入数据。

Java NIO 中的缓冲区有 ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer 和 DoubleBuffer 等,每种缓冲区对应着不同的数据类型。

ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put("Hello, world!".getBytes());
buffer.flip();
while (buffer.hasRemaining()) {
    System.out.print((char) buffer.get());
}

选择器(Selector)

选择器(Selector)是 Java NIO 中的另一个重要组件,它可以用于监控多个通道的事件。

Java NIO 中的选择器(Selector)可以监控多个通道的事件,如连接、读取、写入等事件,并且可以使用单个线程处理多个通道的事件,从而实现高效的网络编程。

try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) {
    serverSocketChannel.bind(new InetSocketAddress("localhost", 8888));
    serverSocketChannel.configureBlocking(false);

    Selector selector = Selector.open();
    serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

    while (true) {
        if (selector.select() == 0) {
            continue;
        }

        Set<SelectionKey> selectedKeys = selector.selectedKeys();
        Iterator<SelectionKey> iterator = selectedKeys.iterator();
        while (iterator.hasNext()) {
            SelectionKey key = iterator.next();
            iterator.remove();

            if (!key.isValid()) {
                continue;
            }

            if (key.isAcceptable()) {
                ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
                SocketChannel clientChannel = serverChannel.accept();
                clientChannel.configureBlocking(false);
                clientChannel.register(selector, SelectionKey.OP_READ);
            } else if (key.is读()) {
                SocketChannel clientChannel = (SocketChannel) key.channel();
                ByteBuffer buffer = ByteBuffer.allocate(1024);
                int bytesRead = clientChannel.read(buffer);
                while (bytesRead > 0) {
                    buffer.flip();
                    while (buffer.hasRemaining()) {
                        System.out.print((char) buffer.get());
                    }
                    buffer.clear();
                    bytesRead = clientChannel.read(buffer);
                }
                if (bytesRead == -1) {
                    clientChannel.close();
                }
            }
        }
    }
} catch (IOException e) {
    e.printStackTrace();
}

文件锁(FileLock)

文件锁(FileLock)是用于在多个进程或线程之间共享文件的一种机制。

Java NIO 中的文件锁(FileLock)可以使用 FileChannel 的 lock() 方法来获取文件锁,也可以使用 tryLock() 方法来尝试获取文件锁。文件锁可以是共享锁或排它锁,共享锁用于读取操作,排它锁用于写入操作。

try (FileChannel channel = FileChannel.open(Paths.get("example.txt"), StandardOpenOption.WRITE)) {
    FileLock lock = channel.lock();
    try {
        ByteBuffer buffer = ByteBuffer.wrap("Hello, world!".getBytes());
        channel.write(buffer);
    } finally {
        lock.release();
    }

5. Java 并发编程

什么是 Java 并发编程

Java 并发编程是指在多线程环境下使用 Java 语言进行编程的一种方式。Java 并发编程主要包括线程、锁、同步、并发容器、线程池等内容。

在 Java 中,可以使用 Thread 类或实现 Runnable 接口来创建线程。锁和同步主要用于对共享资源的访问进行控制,可以使用 synchronized 关键字或 Lock 接口来实现。并发容器可以在多线程环境下使用,并且具有更好的性能和线程安全性。线程池可以用于管理和复用线程,从而提高程序的性能和可靠性。

线程

线程是 Java 并发编程的基础,可以使用 Thread 类或实现 Runnable 接口来创建线程。

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Hello, world!");
    }
}

MyThread thread = new MyThread();
thread.start();
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Hello, world!");
    }
}

Thread thread = new Thread(new MyRunnable());
thread.start();

锁和同步

锁和同步主要用于对共享资源的访问进行控制,可以使用 synchronized 关键字或 Lock 接口来实现。

使用 synchronized 关键字实现同步:

class Counter {
    private int count;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

Counter counter = new Counter();

for (int i = 0; i < 10; i++) {
    new Thread(() -> {
        for (int j = 0; j < 1000; j++) {
            counter.increment();
        }
    }).start();
}

Thread.sleep(1000);

System.out.println(counter.getCount());

使用 Lock 接口实现同步:

class Counter {
    private int count;
    private Lock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }

   public int getCount() {
        lock.lock();
        try {
            return count;
        } finally {
            lock.unlock();
        }
    }
}

Counter counter = new Counter();

for (int i = 0; i < 10; i++) {
    new Thread(() -> {
        for (int j = 0; j < 1000; j++) {
            counter.increment();
        }
    }).start();
}

Thread.sleep(1000);

System.out.println(counter.getCount());

并发容器

并发容器可以在多线程环境下使用,并且具有更好的性能和线程安全性。

Java 中的并发容器包括 ConcurrentHashMap、CopyOnWriteArrayList、CopyOnWriteArraySet 等。

ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();

for (int i = 0; i < 10; i++) {
    new Thread(() -> {
        for (int j = 0; j < 1000; j++) {
            map.put(UUID.randomUUID().toString(), 1);
        }
    }).start();
}

Thread.sleep(1000);

System.out.println(map.size());

线程池

线程池可以用于管理和复用线程,从而提高程序的性能和可靠性。

Java 中的线程池可以使用 ThreadPoolExecutor 类来创建。ThreadPoolExecutor 可以指定核心线程数、最大线程数、任务队列、线程存活时间等参数,以及拒绝策略,用于处理任务队列已满时的情况。

ExecutorService executor = Executors.newFixedThreadPool(10);

for (int i = 0; i < 100; i++) {
    executor.execute(() -> {
        try {
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + " finished task");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
}

executor.shutdown();
executor.awaitTermination(1, TimeUnit.MINUTES);

结语

本文介绍了 Java 的基础知识、面向对象编程、异常处理、IO 编程、并发编程等内容。希望通过本文的学习,读者能够更加深入地理解和掌握 Java 编程语言,为后续的 Java 开发工作打下坚实的基础。

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: IO java 同步锁 并发 并发容器 异步锁 文件 文件对象 线程池 读取 输入 输出
最后更新:2023年 5月 20日

墨风如雪

一个热爱生活,热爱分享的程序员

打赏 点赞
< 上一篇
下一篇 >

文章评论

您需要 登录 之后才可以评论

墨风如雪

一个热爱生活,热爱分享的程序员

最新 热点 随机
最新 热点 随机
美团炸场AI圈:点外卖点出个软件?用「对话式编程」重塑生产力! 当你的证件照学会了眨眼微笑:腾讯混元 HunyuanPortrait 开源,让数字肖像「活过来」! 办公三件套颤抖吧!昆仑万维Skywork超级智能体,给你的办公桌装上AI最强大脑! 字节跳动炸开AI新边界!开源多模态模型BAGEL:这颗“魔法贝果”有多能打? AI“神医”的开源盛宴?谷歌医疗大模型MedGemma来了! 王炸登场!Claude 4 Opus/Sonnet 全平台深度解析:不止聊天,AI真能‘肝’大项目了?
DeepWiki 开源版本:AI 帮你自动写代码 Wiki,告别手动苦海!重塑AI推理格局?微软Phi-4模型震撼发布:轻量化性能炸裂炸裂!微软这门免费AI Agent新手课,GitHub近2万星,简直是宝藏!ComfyUI“打通任督二脉”:直接调用Veo2、GPT-4o等65大模型!一键串联你的AI工作流AI圈炸锅了!Mistral Medium 3:性能 SOTA,成本打骨折,企业玩家的新宠?字节终于开源“扣子”同款引擎了!FlowGram:AI 时代的可视化工作流利器
K8s 安装和部署详解 Redis String 数据结构:基础操作、进阶应用和性能优化 如何使用Java原子类实现自旋锁和读写锁? JAVA当中的异常处理机制核心讲解 谷歌下场,寸草不生?Firebase Studio 挥舞 AI 大棒,誓要统一开发者江湖! 双指针法和归并排序法 - 优化有序数组合并的算法
标签聚合
AI 算法 deepseek spring java 设计模式 教程 动态规划

COPYRIGHT © 2023 墨风如雪博客. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

免责声明 - 隐私政策