Reader和InputStream的区别

本文详细介绍了Java中I/O流的两大体系:InputStream/OutputStream和Reader/Writer的区别及应用场景。探讨了不同类型的输入流如何对应各种数据源,并推荐在处理字符文件时使用基于字符的FileReader和FileWriter。
zz   http://blog.youkuaiyun.com/xiadasong007/article/details/4776913

Reader支持16位的Unicode字符输出,InputStream支持8位的字符输出。

Reader和InputStream分别是I/O库提供的两套平行独立的等级机构,

InputStream、OutputStream是用来处理8位元的流,

Reader、Writer是用来处理16位元的流。

而在JAVA语言中,byte类型是8位的,char类型是16位的,所以在处理中文的时候需要用Reader和Writer。

值得说明的是,在这两种等级机构下,还有一道桥梁InputStreamReader、OutputStreamWriter负责进行InputStream到Reader的适配和由OutputStream到Writer的适配。 
 
java.io.Reader 和 java.io.InputStream 组成了 Java输入类。Reader 用于读入16位字符,也就是 Unicode编码的字符;而 InputStream 用于读入 ASCII字符和二进制数据。


在 Java中,有不同类型的 Reader 输入流对应于不同的数据源:

    FileReader 用于从文件输入;
    CharArrayReader 用于从程序中的字符数组输入;
    StringReader 用于从程序中的字符串输入;
    PipedReader 用于读取从另一个线程中的 PipedWriter 写入管道的数据。
相应的也有不同类型的 InputStream 输入流对应于不同的数据源:FileInputStream,ByteArrayInputStream,StringBufferInputStream,PipedInputStream。另外,还有两种没有对应 Reader 类型的 InputStream 输入流:
    Socket 用于套接字;
    URLConnection 用于 URL 连接。
这两个类使用 getInputStream() 来读取数据。

读写字符文件建议使用基于字符的FileReader和FileWriter,省去了字节与字符之间的转换。
但这两个类的构造函数默认使用系统的编码方式,如果文件内容与系统编码方式不一致,可能会出现乱码。
在这种情况下,建议使用FileReader和FileWriter的父类:InputStreamReader/OutputStreamWriter,
它们也是基于字符的,但在构造函数中可以指定编码类型:InputStreamReader(InputStream in, Charset cs) 和OutputStreamWriter(OutputStream out, Charset cs)。

// 读写文件的编码:
InputStreamReader r = new InputStreamReader(new FileInputStream(fileName), “utf-8″);
OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(fileName),”utf-8″);




相应的,java.io.Writer 和 java.io.OutputStream 也有类似的区别。



<think>我们已知用户想将Reader对象转为InputStream对象,参考提供的引用材料,虽然没有直接提供转换方法,但可以根据流的处理原理来实现。 引用[1]提到了InputStreamReader(将字节流转换为字符流),而我们需要的是反向操作(字符流转字节流)。引用[3]详细介绍了Reader类读取字符数据的方法,以及Writer类写出字符数据。同时,引用[2]展示了如何将字节流包装为字符流(如PrintWriter),这为我们提供了思路:可以使用Writer的字符写出操作配合字节输出流来间接实现。 解决方案: 1. 使用ByteArrayOutputStream作为中间缓冲,将Reader读取的字符数据通过Writer写入到ByteArrayOutputStream,然后从ByteArrayOutputStream获取字节数组,再包装为ByteArrayInputStreamInputStream的子类)。 2. 注意字符编码:在写入时需指定字符集(如UTF-8),否则可能乱码。 步骤: a. 创建ByteArrayOutputStream对象(用于收集字节数据)。 b. 创建OutputStreamWriter对象(将字符流转换为字节流),它将字符编码为字节并写入ByteArrayOutputStream。指定字符编码(如StandardCharsets.UTF_8)。 c. 从Reader中读取字符并写入OutputStreamWriter(使用Reader.readWriter.write方法)。 d. 刷新并关闭流(确保数据全部写入)。 e. 从ByteArrayOutputStream获取字节数组,并用它创建ByteArrayInputStream。 示例代码(Java): ```java import java.io.*; import java.nio.charset.StandardCharsets; public class ReaderToInputStreamExample { public static InputStream convertReaderToInputStream(Reader reader) throws IOException { // 步骤a: 创建字节数组输出流 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // 步骤b: 创建OutputStreamWriter,指定编码 try (OutputStreamWriter writer = new OutputStreamWriter(byteArrayOutputStream, StandardCharsets.UTF_8)) { // 步骤c: 读取Reader中的数据并写入 char[] buffer = new char[1024]; int length; while ((length = reader.read(buffer)) != -1) { writer.write(buffer, 0, length); } // 步骤d: 刷新Writer(确保数据写入底层流) writer.flush(); } // 这里会自动关闭OutputStreamWriter,但不会关闭ByteArrayOutputStream // 步骤e: 从ByteArrayOutputStream获取字节数组并创建输入流 return new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); } } ``` 注意事项: - 此方法会一次性将Reader的所有内容读入内存(因为ByteArrayOutputStream会将所有数据保存在内存中),因此仅适用于数据量不大的情况。对于大文件流,应考虑使用管道流(PipedInputStreamPipedOutputStream)以避免内存溢出,但管道流需要注意死锁问题且实现复杂。 - 关闭处理:在try-with-resources中关闭OutputStreamWriter,但ByteArrayOutputStream不需要关闭(close()方法为空)。注意传入的Reader是否需要在方法外关闭,这里没有关闭传入的Reader(由调用者管理)。 - 字符编码:必须指定与原始字符数据一致的编码,否则转换后数据可能不正确。 另一种方法(使用Apache Commons IO库): 如果项目中可以使用第三方库,Apache Commons IO的`IOUtils`类提供了简便方法: ```java InputStream inputStream = new ByteArrayInputStream(IOUtils.toByteArray(reader, "UTF-8")); ``` 其中`toByteArray`方法内部也是类似的实现。 综上所述,核心思路是利用字符编码将字符流转为字节流,然后包装成InputStream。 相关问题: 1. 如何将InputStream转换为Reader? 2. 在Java中如何处理大文件的字符流到字节流的转换? 3. 字符编码在流转换中的作用是什么? </think>以下是将 `Reader` 对象转换为 `InputStream` 对象的完整解决方案,结合引用材料 Java I/O 流原理逐步说明: --- ### **转换原理与步骤** 1. **核心思路**(引用[1][2][3]): - `Reader` 是**字符流**(处理文本),`InputStream` 是**字节流**(处理二进制) - 转换需通过字符编码(如 UTF-8)将字符转为字节 - 使用 `ByteArrayOutputStream` 作为中间缓冲(引用[2]的字节流操作[^2]) - 通过 `Writer` 写入字符,再提取字节数据(引用[3]的字符流读写机制[^3]) 2. **具体步骤**: ```mermaid graph LR A[Reader 对象] --> B[读取字符数据] B --> C[通过 Writer 写入 ByteArrayOutputStream] C --> D[获取字节数组 byte[]] D --> E[用 ByteArrayInputStream 包装为 InputStream] ``` --- ### **代码实现** ```java import java.io.*; import java.nio.charset.StandardCharsets; public class ReaderToInputStreamConverter { public static InputStream convert(Reader reader) throws IOException { // 步骤1:创建字节缓冲流 ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); // 步骤2:用 Writer 将字符写入字节流(指定编码) try (Writer writer = new OutputStreamWriter(byteStream, StandardCharsets.UTF_8)) { char[] buffer = new char[1024]; int bytesRead; // 循环读取 Reader 数据(引用[3]的 read(char[]) 方法[^3]) while ((bytesRead = reader.read(buffer)) != -1) { writer.write(buffer, 0, bytesRead); } writer.flush(); // 确保数据完全写入 } // 步骤3:将字节流转换为 InputStream return new ByteArrayInputStream(byteStream.toByteArray()); } } ``` --- ### **关键说明** 1. **字符编码的重要性**: - 必须明确指定编码(如 `StandardCharsets.UTF_8`),否则可能乱码 - 编码需与原始数据一致(引用[1]的字符数组转换原则[^1]) 2. **资源管理**: - 使用 `try-with-resources` 确保 `Writer` 自动关闭(引用[3]的语法[^3]) - 原始 `Reader` 需在外部手动关闭 3. **性能优化**: - 缓冲区大小(示例中 `1024`)可根据数据量调整 - 大文件处理需分块读取,避免内存溢出 --- ### **使用示例** ```java // 创建 Reader 对象(示例:从字符串读取) Reader reader = new StringReader("Hello, 你好!"); try (InputStream inputStream = ReaderToInputStreamConverter.convert(reader)) { // 验证转换结果 byte[] data = inputStream.readAllBytes(); System.out.println(new String(data, StandardCharsets.UTF_8)); // 输出: Hello, 你好! } ``` --- ### **适用场景** - 需要将文本数据(如 JSON/XML)传递给仅支持字节流的 API - 加密/压缩算法处理前需统一为字节格式 - 网络传输中兼容二进制协议 --- ### **注意事项** - 如果原始 `Reader` 已关闭,转换会抛出 `IOException` - 非文本数据(如图片)**不应**用此方法,需直接使用字节流 - 编码不一致会导致数据损坏(如中文用 `ISO-8859-1`)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值