我们有一些Java代码,通过使用BufferedReader.readline()
循环访问每个行中的文件来处理用户提供的文件。如何安全地读取可能是二进制的文本文件?
问题是,当用户上传一个具有极长线条的文件时,如任意的二进制JPG或类似文件,这可能会导致内存不足问题。即使是第一个readline()
也可能不会返回。 我们想在它的OOM之前拒绝长行的文件。
有没有一个标准的Java成语来处理这个,或者我们只是改变为read()
并编写我们自己的安全版本readLine()
?
我们有一些Java代码,通过使用BufferedReader.readline()
循环访问每个行中的文件来处理用户提供的文件。如何安全地读取可能是二进制的文本文件?
问题是,当用户上传一个具有极长线条的文件时,如任意的二进制JPG或类似文件,这可能会导致内存不足问题。即使是第一个readline()
也可能不会返回。 我们想在它的OOM之前拒绝长行的文件。
有没有一个标准的Java成语来处理这个,或者我们只是改变为read()
并编写我们自己的安全版本readLine()
?
您将需要通过自己(通过某种形式的read())逐字符(或块大块)读取文件字符,然后在遇到换行符时将这些行形成字符串。这样,如果在遇到换行符之前碰到一些最大数量的字符,则可以抛出异常(避免OOM错误)。
如果您使用Reader实例,实现此代码不应太困难,只需从Reader读取到缓冲区(您分配给最大可能的行长度),然后将缓冲区转换为字符串遇到一个换行符(或者如果你不这样则抛出一个异常)。
使用的BufferedInputStream来读取二进制数据,而不是BufferedReader中...... 例如,如果它是一个图像文件,使用ImageIO的和InputStream中,你可以做这样的..
File file = new File("image.gif");
image = ImageIO.read(file);
InputStream is = new BufferedInputStream(new FileInputStream("image.gif"));
image = ImageIO.read(is);
希望它有助于.. 。
似乎没有成为一个明确的方式,但几件事情可以做:
检查文件头。为此,jMimeMagic似乎是一个非常好的库。
检查文件包含的字符类型。基本上对文件的第一个'x'字节进行统计分析,并用它来估计剩余的内容。
在文件中检查换行'\ n'或'\ r',二进制文件通常不会包含换行符。
希望有所帮助。
似乎没有办法为BufferedReader.readLine()设置行长度限制,所以它会在将代码提供给代码之前积累整行,但是该行可能长。
因此,您必须自己做分线部分,并且一旦线条太长就放弃。
您可能会使用以下为出发点:
class LineTooLongException extends Exception {}
class ShortLineReader implements AutoCloseable {
final Reader reader;
final char[] buf = new char[8192];
int nextIndex = 0;
int maxIndex = 0;
boolean eof;
public ShortLineReader(Reader reader) {
this.reader = reader;
}
public String readLine() throws IOException, LineTooLongException {
if (eof) {
return null;
}
for (;;) {
for (int i = nextIndex; i < maxIndex; i++) {
if (buf[i] == '\n') {
String result = new String(buf, nextIndex, i - nextIndex);
nextIndex = i + 1;
return result;
}
}
if (maxIndex - nextIndex > 6000) {
throw new LineTooLongException();
}
System.arraycopy(buf, nextIndex, buf, 0, maxIndex - nextIndex);
maxIndex -= nextIndex;
nextIndex = 0;
int c = reader.read(buf, maxIndex, buf.length - maxIndex);
if (c == -1) {
eof = true;
return new String(buf, nextIndex, maxIndex - nextIndex);
} else {
maxIndex += c;
}
}
}
@Override
public void close() throws Exception {
reader.close();
}
}
public class Test {
public static void main(String[] args) throws Exception {
File file = new File("D:\\t\\output.log");
// try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(file))) {
// for (int i = 0; i < 10000000; i++) {
// fos.write(65);
// }
// }
try (ShortLineReader r = new ShortLineReader(new FileReader(file))) {
String s;
while ((s = r.readLine()) != null) {
System.out.println(s);
}
}
}
}
注:这是假定UNIX风格的行终止。
如果用户上传一个只有很长行的有效文本文件,会发生什么情况?你还想过滤掉吗? – Jeffrey 2012-03-08 22:27:19
我们的最大值将是5k个字符左右,而这些测试文件的行数包含数百万个字符。 – 2012-03-08 22:29:39