简体   繁体   English

Java BufferedReader.readLine() 不等待 EOL?

[英]Java BufferedReader.readLine() not waiting for EOL?

Sorry if I'm missing something obvious here...but please take a look at this code snippet:对不起,如果我在这里遗漏了一些明显的东西......但请看一下这个代码片段:

String readString;
String writeString = "O hai world.";
BufferedReader br = new BufferedReader(
    new InputStreamReader( 
        new ByteArrayInputStream(writeString.getBytes()),
        "UTF-8"),
    1024);
readString = br.readLine();
System.out.println("readString: " + readString);

I'd expect this to print "readString: null" since I thought the BufferedReader would encounter an EOF before detecting a valid EOL, but instead this prints "readString: O hai world".我希望这会打印“readString: null”,因为我认为 BufferedReader 在检测到有效的 EOL 之前会遇到 EOF,但它会打印“readString: O hai world”。 This seems contrary to what the Javadocs for BufferedReader say readLine() will do:这似乎与 BufferedReader 的 Javadocs 所说的 readLine() 将执行的操作相反:

Reads a line of text.读取一行文本。 A line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or a carriage return followed immediately by a linefeed.一行被认为是由换行符 ('\n')、回车符 ('\r') 或回车符后紧接着换行符中的任何一个终止的。

Returns: A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached返回:包含行内容的字符串,不包括任何行终止字符,如果已到达流末尾则返回 null

I can't see any reason why my string would be re-interpreted to terminate with '\n' and/or '\r'...can someone please illuminate me?我看不出为什么我的字符串会被重新解释为以 '\n' 和/或 '\r' 终止的任何原因...有人可以给我解释一下吗? Thanks!谢谢!

EDIT : To provide some context, I'm trying to write JUnit tests to validate a Reader class that I wrote that's designed to read on System.in.编辑:为了提供一些上下文,我正在尝试编写 JUnit 测试来验证我编写的旨在在 System.in 上读取的 Reader 类。 Using ByteArrayInputStreams seemed like a reasonable way to simulate System.in (see this relevant SO post ).使用 ByteArrayInputStreams 似乎是模拟 System.in 的合理方法(请参阅此相关的 SO 帖子)。

When my Reader captures a line, it currently relies on BufferedReader.readLine().当我的阅读器捕获一行时,它当前依赖于 BufferedReader.readLine()。 For my purposes, my Reader's lines MUST all have been terminated with '\n' or '\r';出于我的目的,我的读者的行必须全部以 '\n' 或 '\r' 结束; encountering EOF without an EOL should not resolve into a valid line.在没有 EOL 的情况下遇到 EOF 不应解析为有效行。 So I guess my question(s) at this point are really as follows (I'll try to test these myself in greater detail when I have time, but hoping you smart folks can help me out):所以我想我此时的问题实际上如下(我会在有时间的时候自己更详细地测试这些问题,但希望聪明的人能帮助我):

  • Is BufferedReader.readLine() broken/misdocumented? BufferedReader.readLine() 损坏/错误记录了吗? Or is ByteArrayInputStream returning something erroneous when its byte array is exhausted?还是 ByteArrayInputStream 在其字节数组耗尽时返回错误的内容?
  • Is this method of testing my Reader erroneous, and should I expect readLine() to function properly when used against System.in?这种测试我的 Reader 的方法是否错误,我是否应该期望 readLine() 在用于 System.in 时正常运行? I'm inclined to believe the answer to this is yes.我倾向于相信这个问题的答案是肯定的。
  • Are there better ways to simulate System.in for unit testing?有没有更好的方法来模拟 System.in 进行单元测试?
  • If I need to strictly discriminate against '\n' and '\r' when reading from an InputStream, am I better off writing my own readLine() method?如果我需要在从 InputStream 读取时严格区分 '\n' 和 '\r',我是否最好编写自己的 readLine() 方法? I'd be very surprised if this is the case.如果是这种情况,我会感到非常惊讶。

Thanks again!再次感谢!

The ByteArrayInputStream doesn't return EOL when it's exhausted. ByteArrayInputStream 在耗尽时不会返回 EOL。 It only returns -1 which might be considered EOF.它只返回 -1,这可能被认为是 EOF。

The thing is that the BufferedReader buffers all it reads from the input stream and if the EOF(-1) is encountered before any EOL character showed up, it returns the string buffered up to that point.问题是 BufferedReader 缓冲它从输入流中读取的所有内容,如果在任何 EOL 字符出现之前遇到 EOF(-1),它会返回缓冲到该点的字符串。

So, if you want to be very strict, you can say that readLine() is either broken according to the current documentation or that it should be documented differently if this was the intended behavior.因此,如果您想要非常严格,您可以说 readLine() 根据当前文档已损坏,或者如果这是预期的行为,则应该以不同的方式记录。

In my opinion, considering that the last line in a stream doesn't have to end with an EOL character (EOF being enough) the current behavior of readLine is correct, ie a line was read because EOF was encountered.在我看来,考虑到流中的最后一行不必以 EOL 字符结尾(EOF 就足够了),readLine 的当前行为是正确的,即读取一行是因为遇到了 EOF。 So, the documentation should be changed.因此,应该更改文档。

I would imagine that this would block would you be reading from a true stream (eg a network socket).我想这会阻止您从真正的流(例如网络套接字)中读取。 But since the underlying input is an array, the reader knows that the true end of data has been reached, so blocking is unnecessary since no new data is forthcoming.但是由于底层输入是一个数组,读取器知道已经到达数据的真正结尾,因此不需要阻塞,因为没有新数据即将到来。 So blocking would be a wrong course of action.因此,阻止将是错误的做法。 Returning a null where actual data was read would also be a wrong thing to do.在读取实际数据的地方返回空值也是错误的做法。

I believe you want a "Robot" to emulate keystrokes for testing purposes:我相信你想要一个“机器人”来模拟击键以进行测试:

This class is used to generate native system input events for the purposes of test automation, self-running demos, and other applications where control of the mouse and keyboard is needed.此类用于生成本机系统输入事件,用于测试自动化、自运行演示和其他需要控制鼠标和键盘的应用程序。 The primary purpose of Robot is to facilitate automated testing of Java platform implementations. Robot 的主要目的是促进 Java 平台实现的自动化测试。

Here's an article that discusses it further:这是一篇进一步讨论它的文章:

What would you expect to happen with this version of your code?您希望此版本的代码会发生什么?

String readString;
String writeString = "O\nhai\nworld.";
BufferedReader br = new BufferedReader(
    new InputStreamReader( 
        new ByteArrayInputStream(writeString.getBytes()),
        "UTF-8"),
    1024);
while (true) {
    readString = br.readLine();
    if (readString == null) break;
    System.out.println("readString: " + readString);
}

The only alternative to what it does now is to throw the final incomplete line away.它现在所做的唯一选择是扔掉最后一个不完整的行。 Not desirable.不可取。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM