如何从缓冲读取器中读取数据?

3

我有一个从缓冲读取器中读取的示例:

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

循环中的代码println将在缓冲读取器(在本例中为input)中出现任何内容时执行。在我的情况下,如果客户端应用程序向套接字写入任何内容,则会执行服务器应用程序中循环中的代码。
但我不理解它是如何工作的。inputLine = input.readLine()会等待直到缓冲读取器中出现内容,并且当有内容出现时,它会返回true并执行循环中的代码。但是,null也可能被返回。
还有一个问题。上述代码来自一个throws Exception方法,我在Thread的run方法中使用此代码。当我尝试在run之前放置throws Exception时,编译器会抱怨:覆盖的方法不会抛出异常。没有throws exception,编译器会抱怨未报告的异常。那么,我该怎么办?

@Roman - 你知道规矩。把不同的问题放在不同的SO问题中! - Stephen C
Stephen C,我以为添加的部分也是“如何从缓冲读取器中读取?”的一部分。但我明白你的意思了。我已经删除了添加的部分。 - Roman
9个回答

5

当另一端的套接字关闭时,读取器应该返回一个空字符串。这是您要查找的条件。为了处理异常,请在读取循环中包装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中从/向套接字读写有关的教程很有帮助。

3

对于你的第一个问题:

但是我不理解它是如何工作的。inputLine = input.readLine()会等待缓冲读取器中出现内容,当有内容出现时,它返回true并执行循环中的代码。但是当null被返回时该怎么办。

BufferedReader.readLine()在成功时不会返回true。它返回包含读取行的字符串。如果到达流的末尾,则返回null

你的第二个问题:

上面的代码是从一个抛出异常的方法中取出来的,我将这个代码用在了Thread的run方法中。当我尝试在run之前加上throws Exception时,编译器会报错:重写的方法不会抛出异常。没有throws exception时,编译器会有另一个错误:未报告的异常。那么我该怎么办呢?

你应该将代码放在try/catch块中。如果你不想处理捕获的异常,可以简单地留空(不建议)。
try {
    while ((inputLine = input.readLine()) != null) {
        System.out.println("I got a message from a client: " + inputLine);
    }
} catch (Exception e) {
    //handle exception
}

1

当读取到内容时,读者的readLine()将返回一个字符串值,当还没有读取到任何内容时,它将返回一个空字符串,当连接关闭时,它将返回null。

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


0

如果这不是为了作业,你可能想要查看Apache Commons IOUtils

假设你不创建BufferedReader,而只停留在InputStream:

String results = IOUtils.toString(inputStream);
System.out.println(results);

0
while ((inputLine = input.readLine()) != null) {

看每个表达式的部分:

input.readLine()

返回一个字符串,如果流的末尾已经到达,则为null(或在出现错误时抛出异常)。
inputLine = input.readLine()

将此字符串分配给inputLine

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

检查被分配的字符串不是 null(流结束)。


0

input读取器连接到套接字,该套接字是一个监听器,即不断监听传入的消息。

关于您的第二个问题,您应该在方法内部放置try/catch块,捕获异常并处理它。不要重新抛出它。


0
但是我不明白它是如何工作的......等待直到缓冲读取器中出现一些内容,当有内容出现时,它返回true。 不,它返回表达式(inputLine = input.readLine())的值,即inputLine本身。 inputLine与null进行比较。

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

0

你已经收到了一些好的答案。只需捕获异常并在本地处理即可。如果您需要将其传递给其他代码,但由于run()方法不允许任何检查异常,因此可以将异常包装在某种RuntimeException中。如果run方法直接在线程上执行(因为它可能是Runnable),则重新抛出包装的异常时应该小心。

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

我有一个警告词,因为您正在使用java.io.BufferedReader包装套接字。您应该非常小心地在任何生产代码中使用它。

问题在于 BufferedReader 在读取过程中无法很好地处理异常。如果您已经在套接字上启用了超时,那么代码将自动从操作系统接收定期异常,这尤其是一个问题。超时(或其他异常)可能会在读者内部的缓冲区正在填充时出现。如果您在异常后尝试重用对象,则它将忽略缓冲区中的任何先前内容。之前接收到的数据包将被静默丢失,并且没有办法检索这些字节。

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

如果在任何异常情况下,您的设计是立即关闭读取器和套接字,则该方法将正常工作。

从套接字读取的正确方法是直接使用套接字流、使用 NIO(ByteBuffers 等)或使用具有良好抽象的良好编写的网络库(有几个开源库可用)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接