Java - чтение из файла. Входной поток против считывателя
В каждой реализации Java, которую я вижу для чтения из файла, я почти всегда вижу, как читатель файлов читает строки за строкой. Я думал, что это будет ужасно неэффективно, потому что для этого требуется системный вызов в строке.
Вместо этого я использовал бы входной поток и напрямую беру байты. В моих экспериментах это значительно быстрее. Мой тест был файлом 1 МБ.
//Stream method
try {
Long startTime = new Date().getTime();
InputStream is = new FileInputStream("test");
byte[] b = new byte[is.available()];
is.read(b);
String text = new String(b);
//System.out.println(text);
Long endTime = new Date().getTime();
System.out.println("Text length: " + text.length() + ", Total time: " + (endTime - startTime));
}
catch (Exception e) {
e.printStackTrace();
}
//Reader method
try {
Long startTime = new Date().getTime();
BufferedReader br = new BufferedReader(new FileReader("test"));
String line = null;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append("\n");
}
String text = sb.toString();
Long endTime = new Date().getTime();
System.out.println("Text length: " + text.length() + ", Total time: " + (endTime - startTime));
}
catch (Exception e) {
e.printStackTrace();
}
Это дает результат:
Text length: 1054631, Total time: 9
Text length: 1034099, Total time: 22
Итак, почему люди используют читателей вместо потоков?
Если у меня есть метод, который принимает текстовый файл и возвращает строку, содержащую весь текст, нужно ли это сделать лучше, используя поток?
Ответы
Ответ 1
Вы сравниваете яблоки с бананами. Чтение одной строки за один раз будет менее эффективным даже при буферизованном считывателе, чем захват данных как можно быстрее. Обратите внимание, что использование доступных не рекомендуется, так как оно неточно во всех ситуациях. Я обнаружил это сам, когда начал использовать потоки шифрования.
Ответ 2
FileReader
обычно используется в сочетании с BufferedReader
, потому что часто имеет смысл читать файл за строкой, особенно если файл имеет четко определенную структуру записи, где каждая запись соответствует строке.
Кроме того, FileReader
может упростить часть работы для обработки кодировок символов и преобразований, как указано в javadocs:
Класс удобства для чтения файлов символов. Конструкторы этого класса предполагают, что кодировка символов по умолчанию и размер байта по умолчанию являются подходящими... FileReader предназначен для чтения потоков символов.
Ответ 3
Попробуйте увеличить размер буфера BufferedReader
. Например:
BufferedReader br = new BufferedReader(new FileReader("test"),2000000);
Если вы выберете правильный размер буфера, вы будете быстрее.
Затем в вашем примере с Reader
вы тратите время на заполнение StringBuilder. Вы должны прочитать файл строки за строкой, если вам нужно обрабатывать строки. Но если вам нужно только прочитать текст в строке, тогда прочитайте больше фрагмента текста с помощью public int read(char[] cbuf)
и напишите фрагменты в StringWriter
, инициализированные с правильным размером.
Выбор использования InputStream
или Reader
не зависит от производительности. Как правило, вы используете Reader
при чтении текстовых данных, потому что с помощью считывателя вы можете более легко обрабатывать кодировку.
Еще один момент, ваш код здесь
byte[] b = new byte[is.available()];
is.read(b);
String text = new String(b);
это неверно. документация сообщает
Обратите внимание, что хотя некоторые реализации InputStream возвращают общее количество байтов в потоке, многие не будут. Неправильно использовать возвращаемое значение этого метода для выделения буфера, предназначенного для хранения всех данных в этом потоке.
поэтому обратите внимание, вам нужно исправить это.