#java #поток_ввода
Зачем понадобилось включать в систему ввода-вывода Java обертку BufferedInputStream, если все реализации интерфейса InputStream по умолчанию содержат метод read(byte b[]), в котором для чтения из потока используется буфер? Для примера, написал программу, которая копирует видеофайл ~100 мб из одного файла в другой. Реализация с использованием BufferedInputStream: public static void main (String[] args) throws IOException{ BufferedInputStream fis=new BufferedInputStream(new FileInputStream("C:/tests/1.mp4")); BufferedOutputStream fos=new BufferedOutputStream(new FileOutputStream("C:/tests/2.mp4")); int b=fis.read(); while (b!=-1){ fos.write(b); b=fis.read(); } fos.flush(); } Реализация с использованием метода read(byte b[]) public static void main (String[] args) throws IOException{ FileInputStream fis=new FileInputStream("C:/tests/1.mp4"); FileOutputStream fos=new FileOutputStream("C:/tests/2.mp4"); byte[] buff=new byte[4096]; int bytes=fis.read(buff); while(bytes!=-1){ fos.write(buff, 0, bytes); bytes=fis.read(buff); } } Реализация с использованием класса BufferedInputStream работает примерно в 10 раз медленнее
Ответы
Ответ 1
Попробуйте сравнить скорость обработки с буферизацией и считыванием массива: BufferedInputStream fis = new BufferedInputStream(new FileInputStream("C:/tests/1.mp4")); BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream("C:/tests/2.mp4")); byte[] buff = new byte[4096]; int bytes = fis.read(buff); while (bytes != -1) { fos.write(buff, 0, bytes); bytes = fis.read(buff); } fos.flush(); Полагаю, что скорость обработки будет сравнима со скоростью без буферизации, а может, даже быстрее, за счет другого размера буфера. Почему первый пример работает медленно Считывание/запись массива байтов из локального файла — очень быстрая операция. В лучше случае BufferedInputStream (BufferedOutputStream) не повлияет на производительность существенным образом, в худшем — производительность упадет из-за различных накладных расходов. В вашем случае байты (~ 10^8) после считывания из буфера обрабатываются по одному, что сильно увеличивает накладные расходы: для каждого байта вызываются методы read и write — вызовы методов не бесплатны; хуже того, оба метода синхронизированные (synchronized) и при каждом вызове виртуальная машина выполняет переключение контекста/блокировку; в самих методах есть разнообразные проверки (открыт ли входной/выходной поток, закончился ли буфер и т.п.), которые также отнимают время. Я полагаю, что основную нагрузку создает синхронизация. Можете для эксперимента добавить синхронизированные методы в вариант с FileInputStream while (bytes != -1) { for (int i = 0; i < bytes; i++) { write(read(buff[i])); } fos.write(buff, 0, bytes); bytes = fis.read(buff); } } static int count = 0; public static synchronized void write(int b) { //неважно count += b; } public static synchronized int read(int b) { return count + b; } Зачем BufferedInputStream Буферизированные потоки нужны чтобы не писать буферизацию самому. Также они позволяют отделить логику программы от настроек буферизации. BufferedInputStream особенно удобен если: Используется алгоритм, который обрабатывает байты последовательно. В этом случае можно упростить код, доверив буферизацию встроенному классу. Сам поток используется в качестве аргумента для класса-чтеца. Например, BufferedInputStream можно передать в качестве аргумента Scanner: Scanner scanner = new Scanner(new BufferedInputStream(new FileInputStream("input"))); После этого через Scanner можно будет работать с данными построчно, а BufferedInputStream сэкономит на обращениях к файловой системе. Используются специфичные методы. Методы InputStream.mark и InputStream.reset, как правило, недоступны в небуферизированных потоках. Соответственно, если потребуется откатывать состояние потока, то использовать FileInputStream не получится. На примере с копированием файла преимущества увидеть сложно. С другой стороны, для копирования файла целесообразнее использовать встроенные методы, а не потоки.
Комментариев нет:
Отправить комментарий