我使用BufferedReader的readLine()
方法从套接字读取文本行。
没有明显的方法来限制读取行的长度。
我担心数据源可能(恶意地或错误地)写入大量数据而没有任何换行符,这将导致BufferedReader分配无限量的内存。
有没有办法避免这种情况?或者我是否必须自己实现readLine()
的有界版本?
答案 0 :(得分:12)
最简单的方法是实现自己的有界线读取器。
甚至更简单,重用this BoundedBufferedReader
class中的代码。
实际上,编码与标准方法相同的readLine()
并非易事。处理3种线路终结器CORRECTLY需要一些非常仔细的编码。将上述链接的不同方法与BufferedReader的Sun version和Apache 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)
这有几种方法:
答案 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
;线路上的任何进一步输入都将被丢弃。