A line-oriented parser should cap each record before accumulating an unbounded String or list of lines.
Java bounded line reader: reject oversized records without buffering the file
Apply the limit while reading
The reader accepts a fixed maximum of content characters per line. A newline ends the record; a preceding carriage return is removed for CRLF input. Count characters as they arrive and reject the first one beyond the limit. Reading every line first and checking lengths afterward loses the memory bound.
The implementation returns null only when EOF arrives before any record character. A final line without a newline is still valid. See file I/O ownership for closing an actual file reader and strict decoding if malformed bytes must be rejected before characters reach this parser.
Define what a character limit means
This limit counts UTF-16 code units because Reader.read returns char values. A protocol limit expressed in UTF-8 bytes or Unicode code points needs a different counter. Keep the unit explicit in the API contract, especially when supplementary characters are permitted.
Working program
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
public class BoundedManifestLine {
static String readLine(Reader source, int maximumChars) throws IOException {
if (maximumChars < 0) throw new IllegalArgumentException("negative limit");
StringBuilder line = new StringBuilder();
int next;
while ((next = source.read()) != -1) {
if (next == '\n') break;
if (line.length() >= maximumChars + 1L) throw new IOException("line too long");
line.append((char) next);
}
if (next == -1 && line.length() == 0) return null;
if (line.length() > 0 && line.charAt(line.length() - 1) == '\r') line.setLength(line.length() - 1);
if (line.length() > maximumChars) throw new IOException("line too long");
return line.toString();
}
public static void main(String[] args) throws IOException {
System.out.println(readLine(new StringReader("lot-47\r\n"), 6));
try { readLine(new StringReader("shipment-82"), 6); }
catch (IOException rejected) { System.out.println(rejected.getMessage()); }
}
}Output
lot-47
line too longCost and ownership
The parser is O(n) in characters read and O(limit) in retained line storage. It allows one extra code unit temporarily so a terminal CR can be distinguished from content, then enforces the final content cap. A Reader still needs a byte-level input cap if decoding expansion or source volume matters.
Common Mistakes
- Do not call readAllLines on an untrusted large file before validation.
- Do not confuse UTF-16 code units with UTF-8 bytes.
- Do not discard a valid last line merely because it lacks a newline.
Read next
Java file I/O: UTF-8, streaming reads, and path ownership, Java UTF-8 decoding: reject malformed bytes before parsing, Java InputStream short reads: assemble a complete record header, Java Stream.close: terminal traversal does not close every source.
