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