我应该如何阅读缓冲读卡器?

我有以下从缓冲读取器读取的示例:

while ((inputLine = input.readLine()) != null) { System.out.println("I got a message from a client: " + inputLine); } 

只要缓冲读卡器中出现某些内容(本例中为input ,就会执行循环println的代码。 在我的例子中,如果客户端应用程序向套接字写入内容,则将执行循环中的代码(在服务器应用程序中)。

但我不明白它是如何工作的。 inputLine = input.readLine()等待缓冲读取器中出现某些内容,当出现某些内容时,它返回true并执行循环中的代码。 但是当null可以返回。

还有一个问题。 上面的代码取自throws Exception的方法,我在Thread的run方法中使用了这段代码。 当我在run之前尝试放置throws Exception ,编译器会抱怨:重写方法不会抛出exception。 没有throws exception我还有另一个来自编译器的抱怨:未报告的exception。 那么,我该怎么办?

当另一端的套接字关闭时,阅读器应返回一个空字符串。 这是您正在寻找的条件。 要处理exception,请将读取循环包装在try / catch块中。

  try { while ((inputLine = input.readLine()) != null) { System.out.println("I got a message from a client: " + inputLine); } } catch (IOException e) { System.err.println("Error: " + e); } 

您可能会发现本教程是使用Java从/向套接字读取/写入有用的。

对于你的第一个问题:

但我不明白它是如何工作的。 inputLine = input.readLine()等待缓冲读取器中出现某些内容,当出现某些内容时,它返回true并执行循环中的代码。 但是当null可以返回。

BufferedReader.readLine()在成功时不返回true 。 它返回一个包含已读取行的String。 如果到达流的末尾,则返回null

你的第二个问题:

上面的代码取自抛出Exception的方法,我在Thread的run方法中使用了这段代码。 当我在运行之前尝试放置抛出exception时,编译器会抱怨:重写方法不会抛出exception。 没有抛出exception,我还有另一个来自编译器的抱怨:未报告的exception。 那么,我该怎么办?

您应该将代码包装在try / catch块中 。 如果您不想处理捕获的exception,只需将该部分留空(不推荐)

 try { while ((inputLine = input.readLine()) != null) { System.out.println("I got a message from a client: " + inputLine); } } catch (Exception e) { //handle exception } 

读取器的readLine()将在读取内容时返回字符串值,在没有任何内容时返回空字符串,并在连接关闭时返回null。

我建议使用IO函数在您的代码块周围包装try / catch并适当地处理错误。

input阅读器连接到套接字,套接字是一个监听器,即继续监听传入的消息。

关于你的第二个问题,你应该在方法中放置一个try / catch块,捕获exception并处理它。 不要重新扔它。

但我不明白它是如何工作的。 ….等待缓冲的阅读器中出现某些内容,当出现某些内容时,它返回true

不,它返回表达式的值(inputLine = input.readLine()),inputLine本身。 inputLine与null进行比较。

当达到“EOF(文件结束)”时返回null。 由于这是从网络套接字读取,因此在套接字断开连接时(由服务器或客户端)创建文件末尾,但在实际看到EOF之前,您可能会收到exception。

如果这不是作业,你可能想看看Apache Commons IOUtils 。

假设您没有创建BufferedReader,只需在InputStream处停止:

 String results = IOUtils.toString(inputStream); System.out.println(results); 
 while ((inputLine = input.readLine()) != null) { 

看一下表达式的每个部分:

 input.readLine() 

返回一个String,如果已到达流的末尾将为null(或者在出错时抛出exception)。

 inputLine = input.readLine() 

将此String分配给inputLine

 ((inputLine = input.readLine()) != null) 

检查分配的字符串是否为空(流结束)。

你收到了一些很好的答案。 抓住exception并在本地处理它。 如果您需要将此传递给其他代码但由于run()方法不允许任何检查exception,则可以将exception包装在某种类型的RuntimeException中。 如果run方法直接在Thread上执行(因为它可能是Runnable),那么你应该注意重新抛出一个包装的exception。

至于readLine()的结果,当没有其他内容可读时,它将返回null 。 在套接字的情况下,这是当另一方干净地关闭套接字时(任何突然终止或不干净关闭通常会导致代码中的exception,因为操作系统将发送不同类型的套接字关闭通知)。

因为你在java.io.BufferedReader中包装一个套接字,所以我有一点需要注意。 在任何类型的生产代码中使用它都应该非常小心。

危险在于BufferedReader在读取过程中不能很好地处理exception。 如果您在套接字上启用了超时,则这尤其是一个问题,因此代码将自动从操作系统接收定期exception。 读取器内的缓冲区正在填充时,可能会发生超时(或其他exception)。 如果在exception之后尝试重用该对象,它将忽略缓冲区中的任何先前内容。 以前收到的数据包会无声地丢失,无法检索这些字节。

请注意,还有其他类型的套接字exception并不意味着套接字已丢失。 例如,查看java.io.InterruptedIOException的定义。 它有一个公共变量,用于报告在最近的I / O(读或写)请求中成功传输的字节数。 这意味着可以再次执行IO操作以检索或发送数据包的剩余字节。

如果在任何例外情况下您的设计是立即关闭阅读器和sockets,则该方法将正常工作。

从套接字读取的正确方法是直接使用套接字流,使用NIO(ByteBuffers等),或者使用编写良好的网络库,对这些较低级别的类具有良好的抽象(可以使用几个开源类)。