簡體   English   中英

Java中BufferedReader.readLine()的最大行長度?

[英]Maximum line length for BufferedReader.readLine() in Java?

我使用BufferedReader的readLine()方法從套接字讀取文本行。

沒有明顯的方法來限制讀取行的長度。

我擔心數據源可能(惡意地或錯誤地)寫入大量數據而沒有任何換行符,這將導致BufferedReader分配無限量的內存。

有沒有辦法避免這種情況? 或者我是否必須自己實現readLine()的有界版本?

最簡單的方法是實現自己的有界線讀取器。

甚至更簡單,重用BoundedBufferedReader類中的代碼。

實際上,編寫與標准方法相同的readLine()編碼並readLine() 處理3種線路終結器CORRECTLY需要一些非常仔細的編碼。 將上述鏈接的不同方法與Sun版本Apache Harmony版本的BufferedReader進行比較是很有趣的。

注意:我並不完全相信有界版本或Apache版本是100%正確的。 有界版本假定底層流支持標記和重置,這當然不總是正確的。 如果將Apache視為緩沖區中的最后一個字符,則Apache版本似乎預讀一個字符。 當讀取用戶輸入的輸入時,這將在MacOS上中斷。 Sun版本通過設置一個標志來處理這個問題,以便在下一次read...操作時跳過CR之后導致可能的LF; 即沒有虛假的預讀。

另一個選擇是Apache Commons的BoundedInputStream

InputStream bounded = new BoundedInputStream(is, MAX_BYTE_COUNT);
BufferedReader reader = new BufferedReader(new InputStreamReader(bounded));
String line = reader.readLine();

也許最簡單的解決方案是采取略微不同的方法。 不是通過限制一個特定讀取來阻止DoS,而是限制讀取的原始數據量。 這樣,只要分配的內存與傳入數據成比例,您就不必擔心每個讀取和循環使用特殊代碼。

您既可以計算Reader ,也可以更適當地計算未解碼的Stream或等效的。

String的限制是20億個字符。 如果您希望限制更小,則需要自己讀取數據。 您可以從緩沖流中一次讀取一個字符,直到達到限制或新行char。

這有幾種方法:

  • 如果整體數據量非常小,則將數據從套接字加載到緩沖區(字節數組,bytebuffer,取決於您喜歡的內容),然后將BufferedReader包裝在內存中的數據周圍(通過ByteArrayInputStream等);
  • 只要捕獲OutOfMemoryError,如果它發生; 捕獲這個錯誤通常是不可靠的,但是在捕獲數組分配失敗的特定情況下,它基本上是安全的(但是沒有解決一個線程從堆中分配大量的線程可能對其他線程造成的任何連鎖效應的問題例如,在你的應用程序中運行);
  • 實現一個只讀取這么多字節的包裝器InputStream,然后在socket和BufferedReader之間插入它;
  • 溝通BufferedReader並通過正則表達式框架分割你的行(實現一個CharSequence,其字符從流中拉出,然后定義一個限制行長度的正則表達式); 原則上,CharSequence應該是隨機訪問,但對於簡單的“行分割”正則表達式,實際上你可能會發現總是請求連續的字符,這樣你就可以在你的實現中“作弊”。

BufferedReader ,不使用String readLine() ,而是使用int read(char[] cbuf, int off, int len) ; 然后你可以使用boolean ready()來查看你是否全部使用構造函數String(byte[] bytes, int offset, int length)將其轉換為字符串。

如果你不關心空白並且你只想擁有每行最多的字符數,那么Stephen建議的提議非常簡單,

import java.io.BufferedReader;
import java.io.IOException;

public class BoundedReader extends BufferedReader {

    private final int  bufferSize;
    private       char buffer[];

    BoundedReader(final BufferedReader in, final int bufferSize) {
        super(in);
        this.bufferSize = bufferSize;
        this.buffer     = new char[bufferSize];
    }

    @Override
    public String readLine() throws IOException {
        int no;

        /* read up to bufferSize */
        if((no = this.read(buffer, 0, bufferSize)) == -1) return null;
        String input = new String(buffer, 0, no).trim();

        /* skip the rest */
        while(no >= bufferSize && ready()) {
            if((no = read(buffer, 0, bufferSize)) == -1) break;
        }

        return input;
    }

}

編輯:這是為了從用戶終端讀取行。 它會阻塞直到下一行,並返回一個bufferSize -bounded String ; 線路上的任何進一步輸入都將被丟棄。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM