Все ответы на данный момент включают чтение файла построчно, взятие строки как 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
подходов, также приведенных в качестве ответов на этот вопрос. В этом вопросе подробно рассматривается очень похожая проблема . Там вы увидите, что есть возможность улучшить его еще больше, если вы захотите пойти по многопоточной линии.