我們有一些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