Java中的I / O流是编程中最容易被误解的概念。
假设我们从套接字连接获取输入流:
DataInputStream in = new DataInputStream(clientSocket.getInputStream());
当我从远程服务器获取数据时,哪些数据能正确描述?
存储在in
变量中的数据。当额外数据来自服务器时,它会附加到in
,从而增加其大小。然后我们可以通过in
变量读取数据:
byte[] messageByte = new byte[1000];
boolean end = false;
String dataString = "";
while(!end)
{
bytesRead = in.read(messageByte);
messageString += new String(messageByte, 0, bytesRead);
if (messageString.length == 100)
{
end = true;
}
}
in
只是指向数据源的链接,不包含数据本身。当我们从套接字调用in.read(messageByte)
1000字节时复制到bytesRead
?
或者,代替套接字,假设我们已将流连接到HDD上的文件。当我们调用in.read(messageByte)
时,我们从HDD读取1000个字节,是吗?
哪种方法是对的?我倾向于认为它是#2,但如果是这样,数据存储在套接字盒中的哪个位置?当我们读取1000个字节时远程服务器是否在等待,然后再次发送额外的数据?或者来自服务器的数据是否存储在操作系统的某个缓冲区中?
答案 0 :(得分:2)
- 存储在变量中的数据。
醇>
没有
当额外数据来自服务器时,它会附加到其中,增加它的大小。然后我们可以通过这种方式从变量中读取数据:
byte[] messageByte = new byte[1000];
boolean end = false;
String dataString = "";
while(!end)
{
bytesRead = in.read(messageByte);
messageString += new String(messageByte, 0, bytesRead);
if (messageString.length == 100)
{
end = true;
}
}
没有。见下文。
- 醇>
in
仅链接到数据源,并且不包含数据本身。
正确。
当我们调用
in.read(messageByte);
1000字节从套接字复制到bytesRead?
没有。它阻止直到:
以先发生者为准。见Javadoc。
(而不是socket,我们可以将流连接到HDD上的文件,当我们调用in.read(messageByte)时,我们从HDD读取1000个字节。是吗?)
没有。与上述相同。
什么方法对吗?
他们两个都没有。从输入流中读取的正确方法是循环,直到您拥有所期望的所有数据,或者发生EOS或异常。您不能依赖read()
填充缓冲区。如果需要,请使用DataInputStream.readFully()
。
我倾向于2
这没有意义。你没有选择。 (1)和(2)不是编程范例,它们是关于流实际如何工作的问题。如何编写代码的问题与此不同。
哪里有数据存储在socket?
其中一些是在内核中的套接字接收缓冲区中。其中大部分还没有到来。它们都不在'插座'中。
或者当我们读取1000个字节时远程服务器正在等待,然后再次发送额外数据?
没有。服务器通过其套接字发送缓冲区发送到套接字接收缓冲区。您的读取和服务器的写入彼此非常分离。
或者来自服务器的数据存储在操作系统的任何缓冲区中?
是的,套接字接收缓冲区。
答案 1 :(得分:1)
这取决于流的类型。存储数据的位置因流而异。有些有内部存储,有些从其他来源读取,有些也有。
当您请求时,FileInputStream
从磁盘上的文件中读取。数据在磁盘上,不在流中。
套接字InputStream
从操作系统缓冲区读取。当数据包到达时,操作系统会自动读取它们并缓冲少量数据(例如64KB)。从流中读取会消耗OS缓冲区。如果缓冲区为空,因为没有数据包到达,则read
调用阻塞。如果你没有足够快地排空缓冲区并且它已满,那么操作系统将丢弃网络数据包,直到你腾出一些空间。
ByteArrayOutputStream
有一个内部byte[]
数组。当您写入流时,它会将您的写入存储在该数组中。在这种情况下,流 具有内部存储。
BufferedInputStream
与另一个输入流相关联。当您从read
BufferedInputStream
时,它通常会从基础流中请求一大块数据并将其存储在缓冲区中。然后,您发出的后续read
请求将满足缓冲区中的数据,而不是在基础流上执行其他I / O.目标是通过发出较少数量的批量读取来最小化底层流接收的单个read
请求的数量。在这种情况下,流具有一些内部存储和一些外部读取的混合策略。