Давайте предположим, что текстовый файл имеет переменную длину строки, и что вы не препроцессором его для создания индекса. (В противном случае должно быть возможно предопределить положение 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 является быстрым, когда отношение мусора к не мусору является высоким. И для программы, которая читает строки сброса, вы в значительной степени гарантированы, что будет так.
Вместо того, чтобы тратить время на то, как быстро сделать вашу программу на основе ложной предпосылки, вам лучше написать простую версию и измерить ее производительность на типичных входных файлах. Только оптимизируйте, если программа фактически слишком медленно.
Выделение и немедленное освобождение миллионов мелких объектов обычно прекрасное. Для виртуальной машины существуют определенные оптимизации. Конечно, это может быть сделано быстрее, но вы сталкиваетесь с проблемой производительности в этой операции пропуска? –
Вы всегда можете написать свой собственный код определения конечной линии, который только считывает байты. Это должно быть немного быстрее (много вызовов для myBufferedInputStream.read() вместо преобразования UTF-8 и создания строк). Конечно, в какой-то момент вам нужно будет преобразовать эти байты в символы ... – tucuxi
Вы действительно запустили это и подтвердили, что это вызывает проблемы с производительностью? – chrylis