Java理解I / O流

时间:2015-10-09 03:47:46

标签: java

Java中的I / O流是编程中最容易被误解的概念。

假设我们从套接字连接获取输入流:

DataInputStream in = new DataInputStream(clientSocket.getInputStream());

当我从远程服务器获取数据时,哪些数据能正确描述?

  1. 存储在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;
        }
    }
    
  2. in只是指向数据源的链接,不包含数据本身。当我们从套接字调用in.read(messageByte) 1000字节时复制到bytesRead

    或者,代替套接字,假设我们已将流连接到HDD上的文件。当我们调用in.read(messageByte)时,我们从HDD读取1000个字节,是吗?

  3. 哪种方法是对的?我倾向于认为它是#2,但如果是这样,数据存储在套接字盒中的哪个位置?当我们读取1000个字节时远程服务器是否在等待,然后再次发送额外的数据?或者来自服务器的数据是否存储在操作系统的某个缓冲区中?

2 个答案:

答案 0 :(得分:2)

  
      
  1. 存储在变量中的数据。
  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;
    }
}

没有。见下文。

  
      
  1. in仅链接到数据源,并且不包含数据本身。
  2.   

正确。

  

当我们调用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请求的数量。在这种情况下,流具有一些内部存储和一些外部读取的混合策略。