2012-03-08 18 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風格的行終止。