2016-06-13 3 views
1

У меня очень большой файл (~ 6 ГБ), который имеет текст фиксированной ширины, разделенный символом \ r \ n, и поэтому я использую буферизованный считыватель для чтения по строкам. Этот процесс может быть прерван или остановлен, и если это так, он использует контрольную точку «lastProcessedLineNbr» для быстрой пересылки в нужное место для возобновления чтения. Так инициализируется читатель.Почему BufferedReader readLine читает прошлое EOF

private void initializeBufferedReader(Integer lastProcessedLineNbr) throws IOException { 
    reader = new BufferedReader(new InputStreamReader(getInputStream(), "UTF-8")); 
    if(lastProcessedLineNbr==null){lastProcessedLineNbr=0;} 

    for(int i=0; i<lastProcessedLineNbr;i++){ 
     reader.readLine(); 
    } 
    currentLineNumber = lastProcessedLineNbr; 
} 

Это, кажется, работает хорошо, и я прочитал и обрабатывать данные в этом методе:

public Object readItem() throws Exception { 
    if((currentLine = reader.readLine())==null){ 
     return null; 
    } 
    currentLineNumber++; 
    return parse(currentLine); 
} 

И опять же, все работает отлично, пока я не достигну последнюю строку в документе. ReadLine() в последнем методе выдает ошибку:

17:06:49,980 ERROR [org.jberet] (Batch Thread - 1) JBERET000007: Failed to run job ProdFileRead, parse, [email protected]: java.lang.OutOfMemoryError: Requested array size exceeds VM limit 
    at java.util.Arrays.copyOf(Arrays.java:3332) 
    at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:137) 
    at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:121) 
    at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:569) 
    at java.lang.StringBuffer.append(StringBuffer.java:369) 
    at java.io.BufferedReader.readLine(BufferedReader.java:370) 
    at java.io.BufferedReader.readLine(BufferedReader.java:389) 
    at com.rational.batch.reader.TextLineReader.readItem(TextLineReader.java:55) 

Любопытно, что, кажется, чтение после конца файла и выделения так много места, что она бежит из памяти. Я попытался посмотреть содержимое файла с помощью Cygwin и «tail file.txt», а в консоли он дал мне ожидаемые 10 строк. Но когда я сделал «tail file.txt> output.txt» output.txt оказался как 1.8GB, намного больше, чем 10 строк, которые я ожидал. Так кажется Cygwin делает то же самое. Насколько я могу судить, нет особого характера EOF. Это всего лишь последний байт данных, и он заканчивается внезапно.

У кого-нибудь есть идеи, как я могу заставить это работать? Я думаю, что могу прибегнуть к подсчету количества прочитанных байтов, пока не получу полный размер файла, но я надеялся, что есть лучший способ.

+0

Конечно, добавление EOF к файлу мне также пришло в голову, но я также не уверен, что это java-способ поместить символ EOF, так как это зависит от ОС. Я бы хотел, чтобы он работал как в Windows, так и в Linux. – joshuar

+1

В Windows или Linux нет «символов EOF». Ctrl-D или Ctrl-Z интерпретируются подсистемой ввода-вывода терминала и сигналом EOF для процесса чтения. Помещение одного из них в файл не будет иметь предполагаемого эффекта. Реальный вопрос в том, что такое содержимое файла в «последней» записи. Из-за исключения появляется последняя «строка» очень большая, достаточно большая, чтобы переполнять доступную память. Вы _sure_ все строки '\ r \ n' разделены? Есть ли пустое пространство, выделенное в файле _after_ последней строки, которая возвращается? –

ответ

1

But when I did tail file.txt > output.txt output.txt ended up being like 1.8GB, much larger than the 10 lines I expected

Что это указывает мне, что файл дополняется с 1,8 Гб двоичных нулей, что команда Cygwin в tail проигнорировано при записи на терминал, но Java не обращая внимания. Это также объясняло бы ваш OutOfMemoryError, так как BufferedReader продолжал читать данные, ищущие следующий \r\n, никогда не нахожу его перед переполнением памяти.

+0

Вероятно, терминал оставил все нули. – EJP

+0

@ EJP, вы правы. Я только что проверил последние 10000 байт, они все равны нулю. У меня просто есть склонность обвинять мою логику программирования, чем вход. Хороший урок для меня. лол. Спасибо вам обоим. – joshuar

Смежные вопросы