Java中BufferedReader.readLine()的最大行长度?

时间:2011-05-11 07:12:49

标签: java readline bufferedreader

我使用BufferedReader的readLine()方法从套接字读取文本行。

没有明显的方法来限制读取行的长度。

我担心数据源可能(恶意地或错误地)写入大量数据而没有任何换行符,这将导致BufferedReader分配无限量的内存。

有没有办法避免这种情况?或者我是否必须自己实现readLine()的有界版本?

6 个答案:

答案 0 :(得分:12)

最简单的方法是实现自己的有界线读取器。

甚至更简单,重用this BoundedBufferedReader class中的代码。

实际上,编码与标准方法相同的readLine()并非易事。处理3种线路终结器CORRECTLY需要一些非常仔细的编码。将上述链接的不同方法与BufferedReader的Sun versionApache Harmony version进行比较是很有趣的。

注意:我并不完全相信有界版本或Apache版本是100%正确的。有界版本假定底层流支持标记和重置,这当然不总是正确的。如果将Apache视为缓冲区中的最后一个字符,则Apache版本似乎预读一个字符。当读取用户输入的输入时,这将在MacOS上中断。 Sun版本通过设置一个标志来处理此问题,以便在下一个read...操作中跳过CR之后导致可能的LF;即没有虚假的预读。

答案 1 :(得分:11)

另一个选择是Apache Commons'BoundedInputStream

InputStream bounded = new BoundedInputStream(is, MAX_BYTE_COUNT);
BufferedReader reader = new BufferedReader(new InputStreamReader(bounded));
String line = reader.readLine();

答案 2 :(得分:3)

也许最简单的解决方案是采取略微不同的方法。不是通过限制一个特定读取来阻止DoS,而是限制读取的原始数据量。这样,只要分配的内存与传入数据成比例,您就不必担心每个读取和循环都使用特殊代码。

您可以计算Reader,或者可能更恰当地计算未解码的Stream或同等数量。

答案 3 :(得分:2)

String的限制是20亿个字符。如果您希望限制更小,则需要自己读取数据。您可以从缓冲流中一次读取一个字符,直到达到限制或新行char。

答案 4 :(得分:1)

这有几种方法:

  • 如果整体数据量非常小,则将数据从套接字加载到缓冲区(字节数组,字节缓冲区,取决于您喜欢的内容),然后将BufferedReader包装在内存中的数据周围(通过ByteArrayInputStream等) ;
  • 只要捕获OutOfMemoryError,如果它发生;捕获这个错误通常是不可靠的,但是在捕获数组分配失败的特定情况下,它基本上是安全的(但是没有解决一个线程从堆中分配大量的线程可能对其他线程造成的任何连锁效应的问题例如,在您的应用程序中运行;
  • 实现一个只读取这么多字节的包装器InputStream,然后在socket和BufferedReader之间插入它;
  • 沟通BufferedReader并通过正则表达式框架分割你的行(实现一个CharSequence,其字符从流中拉出,然后定义一个限制行长度的正则表达式);原则上,CharSequence应该是随机访问,但对于简单的“行分割”正则表达式,实际上你可能会发现总是请求连续的字符,这样你就可以在实现中“作弊”。

答案 5 :(得分:-2)

BufferedReader中,不使用String readLine(),而是使用int read(char[] cbuf, int off, int len);然后,您可以使用boolean ready()查看是否已全部使用构造函数String(byte[] bytes, int offset, int length)将其转换为字符串。

如果你不关心空白,你只想拥有每行最多的字符数,那么Stephen建议的提案非常简单,

import java.io.BufferedReader;
import java.io.IOException;

public class BoundedReader extends BufferedReader {

    private final int  bufferSize;
    private       char buffer[];

    BoundedReader(final BufferedReader in, final int bufferSize) {
        super(in);
        this.bufferSize = bufferSize;
        this.buffer     = new char[bufferSize];
    }

    @Override
    public String readLine() throws IOException {
        int no;

        /* read up to bufferSize */
        if((no = this.read(buffer, 0, bufferSize)) == -1) return null;
        String input = new String(buffer, 0, no).trim();

        /* skip the rest */
        while(no >= bufferSize && ready()) {
            if((no = read(buffer, 0, bufferSize)) == -1) break;
        }

        return input;
    }

}

编辑:这是为了从用户终端读取行。它会阻塞到下一行,然后返回bufferSize - 有界String;线路上的任何进一步输入都将被丢弃。