Java I/O 中的“Stream”和“Buffer”到底是啥意思?
Posted
技术标签:
【中文标题】Java I/O 中的“Stream”和“Buffer”到底是啥意思?【英文标题】:What exactly does "Stream" and "Buffer" mean in Java I/O?Java I/O 中的“Stream”和“Buffer”到底是什么意思? 【发布时间】:2013-04-05 18:33:52 【问题描述】:我刚刚了解了使用BufferedReader
的输入/输出。
我想知道Stream
和Buffer
这两个词的具体含义是什么?
这行代码还有什么作用:
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
【问题讨论】:
【参考方案1】:Java 有两种用于输入和输出 (I/O) 的类:streams 和 readers/writers。
流(InputStream
、OutputStream
以及扩展这些的所有东西)用于从文件、网络或任何其他设备读取和写入二进制数据。
Readers 和 writers 用于读取和写入文本(字符)。它们是流之上的一层,使用character encoding 将二进制数据(字节)转换为字符并返回。
从磁盘逐字节读取数据效率非常低。加速它的一种方法是使用缓冲区:不是一次读取一个字节,而是一次读取几千个字节,然后将它们放入内存中的缓冲区中。然后你就可以一个一个的查看缓冲区中的字节了。
Oracle的Java教程about I/O详细讲解。
查看您提供的代码行:
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
System.in
是一个InputStream
。您创建一个InputStreamReader
,它从System.in
读取字节。然后将其包装在 BufferedReader
中。
所以,最后,您有一个从 InputStreamReader
读取的 BufferedReader
,从 System.in
读取。
【讨论】:
感谢您的回答,但我有一个困惑。正如您所说,我们一次读取几千个字节并将它们放入缓冲区;这是否意味着缓冲区只是我们所在的内存中的一个地方存放东西? @Jesper 。您说“加快速度的一种方法是使用缓冲区:不是一次读取一个字节,而是一次读取几千个字节,然后将它们放入内存中的缓冲区中。然后您可以查看字节一个一个在缓冲区中。”是的,它是真的,但我也认为使用缓冲区,一次读取单个字节。我认为它是放在缓冲区和程序中的唯一区别,然后从缓冲区而不是磁盘读取它 @user122345656 是的,缓冲区是内存中临时存储数据的地方。 @MSach 想想当您想从硬盘读取数据时会发生什么。要读取某个位置的字节,您必须等到磁盘旋转,直到磁头位于磁盘上要读取的字节所在的位置上方。如果此时您只读取 1 个字节,然后再读取下一个字节,则必须等到磁盘完成完整旋转才能读取下一个字节。读取一个连续字节块的效率要高得多。 @parsecer Streams 用于读取字节;阅读器用于阅读文本(字符)。InputStreamReader
是 InputStream
的包装器,允许您从 InputStream
读取文本。如果您只想读取字节(而不是字符),则不需要InputStreamReader
。如果您想将字节解释为文本字符,这很有用。【参考方案2】:
缓冲区:
它是物理内存存储的区域,用于在数据从一个地方移动到另一个地方时临时存储数据。在大多数情况下,物理内存存储将是 RAM(随机存取内存)。
但是从这个问题的上下文来看,Buffer 是在读取/写入数据时使用的。将数据从一个地方移动到另一个地方时不需要使用它。
缓冲区示例:如果您的系统有 4 GB 的 RAM,则系统可以为 Buffer 分配 4 KB 的内存(RAM)。 KB - 千字节,GB - 千兆字节
I/O Stream(或)流:
I/O 流 表示输入源或输出目的地。一条流 可以代表许多不同种类的来源和目的地, 包括磁盘文件、设备、其他程序和内存阵列。
I/O 表示输入/输出。
因此,Input Stream 可以是磁盘文件、网络连接等输入源。
而且,Output Stream 可以是磁盘文件、网络连接等输出目的地。
根据JAVA official documentation,Streams 有 3 种类型。
-
Byte Streams(读取或写入字节)
Character Streams(读取或写入字符)
Buffered Streams(读取或写入缓冲区以提高效率)
字节流:
它们执行 8 位字节的输入和输出。所有字节流类 是InputStream 和OutputStream的后代。
字节输入流类以原始字节的形式获取输入。 字节输出流类以原始字节的形式提供输出。
InputStream
- 直接已知的子类
AudioInputStream, ByteArrayInputStream, FileInputStream, FilterInputStream, InputStream, ObjectInputStream, PipedInputStream, SequenceInputStream, StringBufferInputStream.
OutputStream
- 直接已知的子类
ByteArrayOutputStream, FileOutputStream, FilterOutputStream, ObjectOutputStream, OutputStream, PipedOutputStream
字符流: 它们是字节流之上的一层。它们使用字符编码将字节(二进制数据)转换为字符,将字符转换为字节。
所有字符流类都是Reader和Writer的后代。
Reader
- 直接已知的子类
BufferedReader, CharArrayReader, FilterReader, InputStreamReader, PipedReader, StringReader
Writer
- 直接已知的子类
BufferedWriter, CharArrayWriter, FilterWriter, OutputStreamWriter, PipedWriter, PrintWriter, StringWriter
字节流和字符流使用无缓冲 I/O。
这意味着处理每个读取或写入请求 直接由底层操作系统。这可以使程序少得多 高效,因为每个这样的请求经常触发磁盘访问,网络 活动,或其他一些相对昂贵的操作。 为了减少这种开销,Java 平台实现了缓冲 I/O 流。
缓冲流:
缓冲输入流从称为缓冲区的内存区域读取数据; 仅当缓冲区为空时才调用本机输入 API。
类似地,缓冲输出流将数据写入缓冲区,而 仅当缓冲区已满时才调用本机输出 API。
程序可以将无缓冲流转换为缓冲流 使用包装习语,其中 unbuffered 流对象被传递给 buffered 流类的构造函数。
例子:
inputStream = new BufferedReader(new FileReader("xanadu.txt"));
outputStream = new BufferedWriter(new FileWriter("characteroutput.txt"));
有 4 个缓冲流类用于包装非缓冲流:
要创建缓冲 字节流,请使用BufferedInputStream
和BufferedOutputStream
类。
要创建缓冲 字符流,请使用BufferedReader
和BufferedWriter
类。
【讨论】:
我一直在寻找对 java io 的深入解释。非常感谢。【参考方案3】:嗯,对于开始研究 java.io 包的人来说,这是一个问题。要回答您的问题,术语 InputStreamReader 和 BufferedReader 仅代表 java 对象(它们没有什么特别之处),但它们是为 io 操作创建的,例如从文件、对象等不同的输入/输出读取和写入。
现在让我们开始吧
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
InputStreamReader 是读取字节输入流的类。但是读取每个字节是昂贵的操作,所以我们将它包装在 BufferedReader 周围以使其缓冲(这是装饰器模式)
因此,甚至在您开始读取之前,bufferedReader 将在寄存器中存储一些字节块以及在您执行读取操作时会发生什么。它将从那个位置读取,这比从控制台/文件读取要便宜得多但是对于 InputStreamReader,当您每次执行磁盘访问操作时执行读取操作时
【讨论】:
+1 但我更愿意为信息装饰器添加链接参考,并且每次磁盘访问操作发生时 最后一段很好地总结了好处。谢谢你。【参考方案4】:流是在点之间传递的连接和实际信息。缓冲区是一个存储容器,它存储部分或全部流数据并将其馈送到输出设备。
当然,关键是如果流的速度超过了显示数据所需的数据速率,那么输出就会暂停。缓冲区可以防止这种情况发生。
【讨论】:
感谢您的回答。但我想到的一个问题是流数据是什么意思?请详细说明。 抱歉回复晚了。如果您想象一下服务器上 10Mb 文件的简单示例。服务器有完整的文件,但它不能在一个数据包中发送整个文件。相反,文件被分成有限数量的块。然后将每个块发送到远程计算机,并重新组装。对于流式传输实时数据,同样的理论也适用。但是服务器获取实时数据并将其作为stream
的数据包发送。然后远程计算机将每个数据包存储在缓冲区中。远程计算机从它的缓冲区中读取数据并从中创建一个视频。我希望这会有所帮助!【参考方案5】:
缓冲区是内存中的一部分,用于存储来自外围设备的数据流。然后从这个缓冲区收集这个数据流并将其存储在变量中。流可以定义为连续的数据流。
“输入/输出”这个术语只不过是指将数据移入和移出缓冲区。一直牢记在心。进程通过请求操作系统从缓冲区中排出数据(写入操作)或用数据填充缓冲区(读取操作)来执行 I/O。Logical Diagram of how data moves
简单来说,想象一下当您在键盘上输入数据时,数据通过管道(流)移动到缓冲区,然后从缓冲区移动到磁盘(写操作)。 同样,当数据从磁盘移动到 缓冲区 并从缓冲区移动到控制台时,这就是读取操作。
您可以阅读链接以获得更好的理解。希望对您有所帮助!What is buffer in Javaenter link description here
【讨论】:
以上是关于Java I/O 中的“Stream”和“Buffer”到底是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章