我们有一些Java代码处理用户提供的文件,方法是使用BufferedReader.readline()
遍历文件以读取每一行。
问题在于,当用户上传具有极长行的文件(如任意二进制JPG等)时,这可能会导致内存不足问题。即使是第一个readline()
也可能无法返回。 我们希望在OOM之前拒绝长行的文件。
是否有标准的Java习语来处理这个问题,或者我们只是更改为read()
并编写我们自己的readLine()
安全版本?
答案 0 :(得分:1)
您需要自己逐个字符地阅读文件(或按块分块)(通过某种形式的read()),然后在遇到换行符时将这些行形成为字符串。这样,如果在遇到换行符之前遇到了一些最大字符数,就可以抛出异常(避免OOM错误)。
如果您使用Reader实例,那么实现此代码应该不会太困难,只需从Reader读取到缓冲区(您分配到最大可能的行长度),然后在遇到时将缓冲区转换为String换行符(如果不换行则抛出异常)。
答案 1 :(得分:1)
似乎没有任何方法可以为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样式的行终止。
答案 2 :(得分:0)
使用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);
希望它有所帮助...
答案 3 :(得分:0)
似乎没有明确的方法,只能做一些事情:
检查文件标题。 jMimeMagic似乎是一个非常好的库。
检查文件包含的字符类型。基本上对文件的第一个“x”字节进行统计分析,并使用它来估计其余内容。
检查文件中的换行符'\ n'或'\ r',二进制文件通常不包含换行符。
希望有所帮助。