【问题标题】:BufferedReader - read all characters (not lines)BufferedReader - 读取所有字符(不是行)
【发布时间】:2018-06-16 02:05:14
【问题描述】:

如何使用BufferedReader 将所有可用字符读入String

我有一个Socket,我想从中读取数据(如果可用)并将其存储在String 中。问题是,我不能使用readLine,因为我收到的数据并不总是包含换行符或插入符号返回,并且readLine 会阻塞线程,直到它可以读取整行。如何改用read

thread = new Thread(() ->
    {
        try {
            out = new PrintWriter(client.getOutputStream(), true);
            in = new BufferedReader(new InputStreamReader(client.getInputStream()));

             while(true) 
             {
                if (in.ready())
                {
                    String someString = // ? read available data
                    delegate.didReadData(this, someString);
                }
             }

        } catch (IOException e) {
            delegate.didDropSocket(this);
        }
    });
    thread.start();

编辑
1. 代表不关心字符串有多长,它只需要处理通过套接字到达的任何 hada - 以及它的全部内容
2. 我不需要将数据切割成块 - 我想读取所有到达的内容
3. 是的,我有一个无限循环,因为我需要保持连接到套接字并监听数据,直到客户端断开连接 - 当我收到 IOException 时。我为套接字使用了一个单独的线程,因为会有更多的套接字要监听。

【问题讨论】:

  • 这不是一个可行的方法。您的 while(true)if(ready) 是 NIO 选择器的低效仿真。它要么是 read(byte[] buffer) 上的线程阻塞(请注意,如果使用像 UTF-8 这样的多字节编码,这会增加复杂性),要么是 NIO,因为您似乎没有遵循任何协议。您还可以描述您想要达到的实际最终结果,以便我们向您建议适当的解决方案。目前你已经偏离了标准。
  • 我不知道 NIO 是什么,我是 Java 新手,这是一个副项目。一般来说,我想做的是:我想监听任何尝试连接到我的程序的客户端套接字,当它们连接时,我想读取和处理任何到达的数据。该应用程序将具有 GUI,因此从套接字读取不会阻塞主线程。我的方法不可行的任何特殊原因?就像我说的,我是 Java 新手
  • 因为套接字的工作方式是你说“我想读取数据”,然后在某个时候你得到一些字节,然后你对这些字节做一些事情。您的代码正在尝试做类似的事情,但使用文本。当您使用文本时,很容易拥有基于行的协议,但您正在尝试做一些不同的事情。看起来您可能想要 read(byte[] buf) 方法上的块,然后在它们到达时将它们转换为字符。阻塞不是问题,这就是为什么首先使用线程进行套接字通信的原因。如果您是 Java 新手,那会很复杂。
  • 好的,我在文档中看到 Reader 的 read(char[] cbuf) 是一个阻塞调用,因为在我的情况下,每个套接字都使用单独的线程,所以效果很好。你能举个例子说明如何使用该功能吗?

标签: java bufferedreader


【解决方案1】:

您需要始终明确指定您正在使用哪种编码,您无需在阅读前检查,当然您必须跟踪您阅读了多少以及另一端是否关闭了连接.

省略了异常处理和资源关闭。如有必要,可以增加缓冲区大小。否则,这是一个非常惯用的读取循环。

out = new PrintWriter(client.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(client.getInputStream(), StandardCharsets.UTF_8));
char[] buf = new char[4096];
int size = 0;
while((size = in.read(buf)) != -1) {
    String someString = new String(buf, 0, size);
    delegate.didReadData(this, someString);
}

【讨论】:

    【解决方案2】:

    BufferedReader#readLine(0) treats '\n'、'\r' 和 "\r\n" 作为行分隔符。这种行为无法改变,所以正如你所说,我们需要使用read 的两个重载之一。

    delegate 需要什么?它关心someString 有多长吗?您是否需要“分块”从in 读取的数据?你确定String合适吗?

    我怀疑你想要read(char[] cbuf, int off, int len) 方法。

    假设您需要一次读取一个字符,使用 read 的一次块重载会比使用一个-一次一个字符重载。

    另外,你有一个无限循环。即使 ready 返回 false,您的代码也不会终止,因为您永远不会离开 while(true) 循环。

    或者这里的意图是让线程不断检查更多数据,没有尽头?我对 Java 标准库不够熟悉,无法提供详细信息,但我相信有更好的方法来做到这一点,而不是让线程以 100% 的负载运行您的一个内核,检查额外的数据。简单的技巧是添加一个sleep 调用,但我相信有更好的方法,可能涉及Stream 类。

    【讨论】:

    • 查看编辑以获取问题的答案。如何使用 read read(char[] cbuf, int off, int len) 一次读取缓冲区的所有内容?
    • 我写了一个很长的回复,然后注意到 - 我认为你想要 StringWriter 类,而不是 BufferedReaderBufferedReaderBufferedWriter 类不公开其内部缓冲区 - 无法将内容转储到字符串。
    猜你喜欢
    • 2013-03-23
    • 2010-09-07
    • 1970-01-01
    • 2015-05-12
    • 2013-09-26
    • 2017-11-18
    • 2019-10-17
    • 1970-01-01
    • 2013-10-30
    相关资源
    最近更新 更多