Все приведенные до сих пор ответы включают чтение файла построчно, ввод строки как a String
, а затем обработку файла String
.
Несомненно, это самый простой для понимания подход, и если файл достаточно короткий (скажем, десятки тысяч строк), он также будет приемлемым с точки зрения эффективности. Но если файл длинный , это очень неэффективный способ сделать это по двум причинам:
- Каждый символ обрабатывается дважды: один раз при построении
String
и один раз при обработке.
- Сборщик мусора не будет вашим другом, если в файле много строк. Вы создаете новый
String
для каждой строки, а затем выбрасываете его, когда переходите к следующей строке. Сборщик мусора в конечном итоге должен будет избавиться от всех этих String
объектов, которые вам больше не нужны. Кто-то должен убирать за тобой.
Если вы заботитесь о скорости, вам гораздо лучше прочитать блок данных, а затем обработать его побайтно, а не построчно. Каждый раз, когда вы подходите к концу числа, вы добавляете его к List
создаваемому вами.
Получится примерно так:
private List<Integer> readIntegers(File file) throws IOException {
List<Integer> result = new ArrayList<>();
RandomAccessFile raf = new RandomAccessFile(file, "r");
byte buf[] = new byte[16 * 1024];
final FileChannel ch = raf.getChannel();
int fileLength = (int) ch.size();
final MappedByteBuffer mb = ch.map(FileChannel.MapMode.READ_ONLY, 0,
fileLength);
int acc = 0;
while (mb.hasRemaining()) {
int len = Math.min(mb.remaining(), buf.length);
mb.get(buf, 0, len);
for (int i = 0; i < len; i++)
if ((buf[i] >= 48) && (buf[i] <= 57))
acc = acc * 10 + buf[i] - 48;
else {
result.add(acc);
acc = 0;
}
}
ch.close();
raf.close();
return result;
}
В приведенном выше коде предполагается, что это ASCII (хотя его можно легко настроить для других кодировок), и что все, что не является цифрой (в частности, пробел или новая строка), представляет собой границу между цифрами. Он также предполагает, что файл заканчивается не цифрой (на практике последняя строка заканчивается новой строкой), хотя, опять же, его можно настроить, чтобы справиться со случаем, когда это не так.
Это намного, намного быстрее, чем любой из String
подходов на основе, также приведенных в качестве ответов на этот вопрос. В этом вопросе есть подробное исследование очень похожей проблемы . Там вы увидите, что есть возможность улучшить его еще больше, если вы хотите перейти на многопоточную линию.