2014-02-05 4 views
1

Я хочу знать, как напрямую достичь определенной строки текстового файла в java. Один метод - это.goto номер строки строки в Java

int line=0; 
BufferedReader read=new BufferedReader(new FileReader(Filename)); 
while(read.readLine()!=null){ 
    line++; 
    if(line==LIMIT) break; 
} 

Но это создаст много объектов String, которые не будут освобождены, если только gc не запустится. Пожалуйста, предоставьте решение, которое будет быстрым и не будет потреблять много памяти.

PS: Я читаю из файла, который имеет миллионы строк.

+7

Выделение и немедленное освобождение миллионов мелких объектов обычно прекрасное. Для виртуальной машины существуют определенные оптимизации. Конечно, это может быть сделано быстрее, но вы сталкиваетесь с проблемой производительности в этой операции пропуска? –

+0

Вы всегда можете написать свой собственный код определения конечной линии, который только считывает байты. Это должно быть немного быстрее (много вызовов для myBufferedInputStream.read() вместо преобразования UTF-8 и создания строк). Конечно, в какой-то момент вам нужно будет преобразовать эти байты в символы ... – tucuxi

+0

Вы действительно запустили это и подтвердили, что это вызывает проблемы с производительностью? – chrylis

ответ

-2

Я думаю, что это должно помочь:

FileReader fr = new FileReader("file1.txt"); 
BufferedReader br = new BufferedReader(fr); 

LineIterator it = IOUtils.lineIterator(br); 
for (int l = 0; it.hasNext(); l++) { 
    String line = (String) it.next(); 
    if (l == LIMIT) { 
     return line; 
    } 
} 
+1

Можете ли вы объяснить, как это может быть быстрее? –

+3

Это не отвечает ни одной из проблем OP. Он выделяет все строки, как и текущий код. –

+2

Несомненно, он ничего не решает, но эй: он добавил зависимость сторонней библиотеки. Поэтому он должен * быть лучше, чем простой Java-код ... – Holger

2

Давайте предположим, что текстовый файл имеет переменную длину строки, и что вы не препроцессором его для создания индекса. (В противном случае должно быть возможно предопределить положение N-й линии, а затем «искать» ее).

Первое наблюдение заключается в том, что (с приведенными выше предположениями) невозможно найти N-ю строку без изучая каждого персонажа перед началом N-й линии.

Но вы все равно можете сделать это таким образом, чтобы не генерировать много мусора. Вот простой вариант:

BufferedReader br = new BufferedReader(new FileReader(filename)); 
for (int i = 1; i < LIMIT; i++) { 
    while ((ch = br.read()) != '\n') { 
     if (ch == -1) { 
      // reached the end of file too soon ... 
      throw new IOException("The file has < " + LIMIT + " lines"); 
     } 
    } 
} 
line = br.readLine(); 

Хитрость заключается в том, чтобы пропустить линии без их формирования в String объектов.

В настоящее время существует небольшой недостаток в приведенном выше. Предполагается, что строки текстового файла заканчиваются символом новой строки ('\n'), тогда как readLine может справиться с тремя видами разделителей строк. Но это можно было бы решить ... без создания лишнего мусора. Я оставлю это «упражнением для читателя», а также проведет исследования, используя read(char[]) вместо read().

Вы могли бы получить более высокую производительность, если вы открыли файл с помощью FileInputStream, получили FileChannel, прочитать байты в ByteBuffer, а затем искали его (byte) '\n'. Но код значительно сложнее.


Однако я хотел бы укрепить точку, высказанную в комментариях. Вы возможно тратите свое время на это. Скорее всего, ваша оригинальная версия работает достаточно быстро для ваших целей, несмотря на создание большого количества мусора. В действительности, GC является быстрым, когда отношение мусора к не мусору является высоким. И для программы, которая читает строки сброса, вы в значительной степени гарантированы, что будет так.

Вместо того, чтобы тратить время на то, как быстро сделать вашу программу на основе ложной предпосылки, вам лучше написать простую версию и измерить ее производительность на типичных входных файлах. Только оптимизируйте, если программа фактически слишком медленно.

0

Вместо чтения строк вы можете считывать данные в блоках (может быть 1024 байта) и символов строки поиска. Чтобы прочитать блок данных, вы можете использовать массив byte, поэтому он будет использоваться повторно, поэтому проблем с памятью не возникает.Вы должны заботиться о:

  • Обработка обоих \r и \n символов
  • Кодировка файла (как Unicode или другой)

чтения данных в блоках вместо побайтно будет более эффективным.

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