2012-03-08 19 views
2

我们有一些Java代码,通过使用BufferedReader.readline()循环访问每个行中的文件来处理用户提供的文件如何安全地读取可能是二进制的文本文件?

问题是,当用户上传一个具有极长线条的文件时,如任意的二进制JPG或类似文件,这可能会导致内存不足问题。即使是第一个readline()也可能不会返回。 我们想在它的OOM之前拒绝长行的文件。

有没有一个标准的Java成语来处理这个,或者我们只是改变为read()并编写我们自己的安全版本readLine()

+1

如果用户上传一个只有很长行的有效文本文件,会发生什么情况?你还想过滤掉吗? – Jeffrey 2012-03-08 22:27:19

+0

我们的最大值将是5k个字符左右,而这些测试文件的行数包含数百万个字符。 – 2012-03-08 22:29:39

回答

1

您将需要通过自己(通过某种形式的read())逐字符(或块大块)读取文件字符,然后在遇到换行符时将这些行形成字符串。这样,如果在遇到换行符之前碰到一些最大数量的字符,则可以抛出异常(避免OOM错误)。

如果您使用Reader实例,实现此代码不应太困难,只需从Reader读取到缓冲区(您分配给最大可能的行长度),然后将缓冲区转换为字符串遇到一个换行符(或者如果你不这样则抛出一个异常)。

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); 

希望它有助于.. 。

0

似乎没有成为一个明确的方式,但几件事情可以做:

  1. 检查文件头。为此,jMimeMagic似乎是一个非常好的库。

  2. 检查文件包含的字符类型。基本上对文件的第一个'x'字节进行统计分析,并用它来估计剩余的内容。

  3. 在文件中检查换行'\ n'或'\ r',二进制文件通常不会包含换行符。

希望有所帮助。

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风格的行终止。