在Java编程的广阔天地中,数据的流动如同一条条看不见的河流,滋养着程序的生命力。而流(Stream)作为数据传输的核心机制,承载着数据的读写重任。今天,我们将深入探讨字节流与字符流的精妙之处,解锁它们背后的编程艺术。

第一章:字节流的基石 —— 构建数据的桥梁

字节流是Java中用于处理二进制数据的基础,它们以8位字节的形式传输数据。在Java标准库中,java.io.InputStreamjava.io.OutputStream是所有字节流的根类,提供了读取和写入数据的基本方法。

1.1 文件输入/输出流

FileInputStreamFileOutputStream是最常用的字节流,用于读写文件系统中的数据。

示例:读取文件内容

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

public class FileInputStreamExample {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("path/to/file.bin")) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                System.out.println(new String(buffer, 0, bytesRead));
            }
        } catch (IOException e) {
            System.err.println("读取文件失败:" + e.getMessage());
        }
    }
}

1.2 缓冲字节流

为了提高性能,BufferedInputStreamBufferedOutputStream提供了带有内部缓冲区的字节流,减少了系统调用的频率。

示例:使用缓冲字节流

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

public class BufferedInputStreamExample {
    public static void main(String[] args) {
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("path/to/file.bin"))) {
            int data;
            while ((data = bis.read()) != -1) {
                System.out.print((char) data);
            }
        } catch (IOException e) {
            System.err.println("读取文件失败:" + e.getMessage());
        }
    }
}

第二章:字符流的篇章 —— 文本的优雅表达

字符流专门用于处理文本数据,它们以字符为单位进行读写,通常使用java.io.Readerjava.io.Writer作为基类。

2.1 字符输入/输出流

FileReaderFileWriter是字符流中用于文件读写的常见实现。

示例:写入文本到文件

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

public class FileWriterExample {
    public static void main(String[] args) {
        try (FileWriter writer = new FileWriter("path/to/file.txt")) {
            writer.write("Hello, world!");
            writer.flush();
        } catch (IOException e) {
            System.err.println("写入文件失败:" + e.getMessage());
        }
    }
}

2.2 缓冲字符流

BufferedReaderBufferedWriter提供了一种高效的方式来读写字符数据,内置的缓冲区可以显著提高性能。

示例:逐行读取文本文件

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

public class BufferedReaderExample {
    public static void main(String[] args) {
        try (BufferedReader reader = new BufferedReader(new FileReader("path/to/file.txt"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.err.println("读取文件失败:" + e.getMessage());
        }
    }
}

第三章:流的高级应用 —— 装饰器模式与自定义流

Java中的流设计采用了装饰器模式,允许在已有的流上添加额外的功能而不改变其接口。

3.1 装饰器模式示例

例如,PrintStream就是一个装饰器,它可以将字节流转换为打印流,提供方便的格式化输出方法。

示例:使用PrintStream

import java.io.PrintStream;

public class PrintStreamExample {
    public static void main(String[] args) {
        try (PrintStream ps = new PrintStream(System.out)) {
            ps.printf("The answer is %d\n", 42);
        }
    }
}

3.2 自定义流的封装

你还可以创建自己的流类来满足特定需求,如压缩流GZIPOutputStreamGZIPInputStream,或者加密流等。

示例:创建自定义计数输出流

import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class CountingOutputStream extends FilterOutputStream {
    private int count = 0;

    public CountingOutputStream(OutputStream out) {
        super(out);
    }

    @Override
    public void write(int b) throws IOException {
        super.write(b);
        count++;
    }

    public int getCount() {
        return count;
    }
}

// 使用示例
public class UseCountingOutputStream {
    public static void main(String[] args) {
        try (OutputStream out = new CountingOutputStream(System.out)) {
            out.write("Hello, World!".getBytes());
            CountingOutputStream cos = (CountingOutputStream) out;
            System.out.println("字符总数:" + cos.getCount());
        } catch (IOException e) {
            System.err.println("写入时发生错误:" + e.getMessage());
        }
    }
}

第四章:流的管理 —— 资源释放与异常处理

在使用流时,资源管理和异常处理至关重要。Java 7引入了try-with-resources语句,自动关闭实现了AutoCloseable接口的资源,简化了代码。

示例:使用try-with-resources

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

public class TryWithResourcesExample {
    public static void main(String[] args) {
        try (BufferedReader reader = new BufferedReader(new FileReader("path/to/file.txt"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.err.println("读取文件失败:" + e.getMessage());
        }
    }
}