- Простой способ записи содержимого Java InputStream в OutputStream
- 20 ответов
- Java 9
- Простая Функция
- InputStream/OutputStream
- Потоки вывода, OutputStream
- Выходной поток OutputStream
- Класс ByteArrayOutputStream
- Класс FileOutputStream
- Класс BufferedOutputStream
- Класс DataOutputStream
- Класс PrintStream
- Класс ObjectOutputStream
- Класс PipedOutputStream
Простой способ записи содержимого Java InputStream в OutputStream
Я был удивлен, обнаружив сегодня, что я не мог отследить простой способ написать содержимое InputStream до OutputStream в Java. Очевидно, что код буфера байтов не сложно написать, но я подозреваю, что мне просто не хватает чего-то, что облегчило бы мою жизнь (и код яснее).
Итак, дано InputStream in и OutputStream out , есть ли более простой способ написать следующее?
20 ответов
если вы используете Java 7, файлы (в стандартной библиотеке) является лучшим подходом:
Edit: конечно, это просто полезно, когда вы создаете один из InputStream или OutputStream из файла. Использовать file.toPath() чтобы получить путь из файла.
для записи в существующий файл (например, созданный с помощью File.createTempFile() ), вам нужно будет пройти REPLACE_EXISTING опция копирования (в противном случае FileAlreadyExistsException выбрасывается):
как упоминалось WMR, org.apache.commons.io.IOUtils из Apache имеет метод, называемый copy(InputStream,OutputStream) что делает именно то, что вы ищете.
Итак, у вас есть:
есть ли причина, по которой вы избегаете IOUtils ?
Я думаю, что это сработает, но обязательно проверьте его. незначительное «улучшение», но это может быть немного стоить при удобочитаемости.
Java 9
Начиная С Java 9, InputStream предоставляет метод под названием transferTo со следующей подписью:
как документация государства transferTo будет:
считывает все байты из входного потока и записывает байты в заданный выходной поток в том порядке, в котором они считываются. По возвращении, это входной поток будет в конце потока. Этот метод не закрывается любой поток.
этот метод смогите преградить неопределенно чтение от входной поток или запись в выходной поток. Поведение случай, когда входной и/или выходной поток асинхронно закрыт, или поток прерванный во время передачи, сильно входной сигнал и выход поток специфичен, и поэтому не указан
Итак, чтобы написать содержимое Java InputStream до OutputStream , вы можете написать:
Простая Функция
Если вам нужно только это написать InputStream до File затем вы можете использовать эту простую функцию:
PipedInputStream и PipedOutputStream следует использовать только при наличии нескольких потоков, как отмечено Javadoc.
кроме того, обратите внимание, что входные и выходные потоки не обертывают прерывания потока с помощью IOException s. Таким образом, вы должны рассмотреть возможность включения политики прерывания в свой код:
Это было бы полезным дополнением, если вы ожидаете использовать этот API для копирования больших объемов данных или данных из потоков, которые застревают для невыносимо долго.
на JDK использует тот же код, поэтому кажется, что нет «более простого» способа без неуклюжих сторонних библиотек (которые, вероятно, не делают ничего другого в любом случае). Следующее непосредственно копируется из java.nio.file.Files.java :
нет способа сделать это намного проще с помощью методов JDK, но, как уже отметил Apocalisp, вы не единственный с этой идеей: вы можете использовать IOUtils С Jakarta Commons IO, у него также есть много других полезных вещей, которые ИМО на самом деле должны быть частью JDK.
использование Java7 и try-with-resources, поставляется с упрощенной и читаемый вариант.
для тех, кто использует весенние рамки есть полезное StreamUtils класс:
вышеизложенное не закрывает потоки. Если вы хотите, чтобы потоки были закрыты после копирования, используйте FileCopyUtils класс:
Источник
InputStream/OutputStream
— Привет, Амиго! Сегодня мы снова будем заниматься разбором работы InputStream и OutputStream. На самом деле, то первое объяснение было немного упрощенным. Это не интерфейсы, а абстрактные классы, и они даже имеют по паре реализованных методов. Давай посмотрим, какие методы у них есть:
Методы класса InputStream | Что метод делает |
---|---|
— метод сразу читает блок байт в буфер ( массив байт ), пока буфер не заполнится или не закончатся байты там, откуда он их читает. Метод возвращает количество реально прочитанных байт (оно может быть меньше длины массива) | |
— метод читает один байт и возвращает его как результат. Результат расширяется до int, для красоты. Если все байты уже прочитаны, метод вернет «-1». | |
— метод возвращает количество непрочитанных (доступных) байт. | |
— метод «закрывает» поток – вызывается после окончания работы с потоком. Объект выполняет служебные операции, связанные с закрытием файла на диске и т.д. Из потока больше нельзя читать данные. |
— Т.е. мы можем читать не только по одному байту, а и целыми блоками?
— А записывать целыми блоками тоже можно?
Методы OutputStream | Что метод делает |
---|---|
— метод записывает один байт информации. Тип int сужается до byte, лишняя часть просто отбрасывается. | |
— метод записывает блок байт. | |
— метод записывает часть блока байт. Используется в случаях, когда есть вероятность, что блок данных был заполнен не целиком | |
— если есть данные, которые хранятся где-то внутри и еще не записаны, то они записываются. | |
— метод «закрывает» поток – вызывается после окончания работы с потоком. Объект выполняет служебные операции, связанные с закрытием файла на диске и т.д.В поток больше нельзя писать данные, flush при этом вызывается автоматически. |
— А как будет выглядеть код копирования файла, если мы будем читать не по одному байту, а целыми блоками?
— Гм. Примерно так:
— С буфером все понятно, а что это за переменная count?
— Когда мы читаем самый последний блок данных в файле, может оказаться, что байт осталось не 1000, а, скажем, 328. Тогда и при записи нужно указать, что записать не весь блок, а только его первые 328 байт.
Метод read при чтении последнего блока вернет значение равное количеству реально прочитанных байт. Для всех чтений – 1000, а для последнего блока – 328.
Поэтому при записи блока мы указываем, что нужно записать не все байты из буфера, а только 328 (т.е. значение, хранимое в переменной count).
— Теперь понятно, как все это работает. Спасибо, Элли.
Источник
Потоки вывода, OutputStream
Стандартная библиотека Java имеет весьма развитые средства вывода данных. Все возможности вывода данных сосредоточены в пакете java.io.
Существуют две параллельные иерархии классов вывода : OutputStream и Writer. Класс Writer введен в последних версиях Java.
В данной статье рассматривается вопрос использования потоков для вывода данных в файл. Иерархии выходных OutputStream потоков представлена на следующем рисунке.
Поток Stream— это абстрактное значение источника или приёмника данных, которые способны обрабатывать информацию. Есть два типа потоков: байтовые и символьные. В некоторых ситуациях символьные потоки более эффективны, чем байтовые. Классы, производные от классов OutputStream или Writer, имеют методы с именами write() для записи одиночных байтов или массива байтов (отвечают за вывод данных).
Выходной поток OutputStream
Класс OutputStream — это абстрактный класс, определяющий байтовый поток вывода. Наследники данного класса определяют куда направлять данные: в массив байтов, в файл или канал. Из массива байт можно создать текстовую строку String.
Методы класса OutputStream :
- void write(int b) записывает один байт в выходной поток. Аргумент этого метода имеет тип int, что позволяет вызывать write, передавая ему выражение, при этом не нужно выполнять приведение его типа к byte.
- void write(byte b[]) записывает в выходной поток весь указанный массив байтов.
- void write(byte b[], int off, int len) записывает в поток len байтов массива, начиная с элемента b[off].
- void flush() очищает любые выходные буферы, завершая операцию вывода.
- void close() закрывает выходной поток. Последующие попытки записи в этот поток будут возбуждать IOException.
Класс ByteArrayOutputStream
Класс ByteArrayOutputStream представляет поток вывода, использующий массив байтов в качестве места вывода. Чтобы создать объект данного класса, можно использовать один из его конструкторов :
Первый конструктор создает массив данных для хранения байтов длиной в 32 байта, а второй конструктор создает массив длиной size.
Примеры использования класса ByteArrayOutputStream :
В классе ByteArrayOutputStream метод write записывает в поток некоторые данные (массив байтов). Этот массив байтов записывается в объекте ByteArrayOutputStream в защищенное поле buf, которое представляет также массив байтов (protected byte[] buf). Так как метод write может вызвать исключение, то вызов этого метода помещается в блок try..catch.
Используя методы toString() и toByteArray(), можно получить массив байтов buf в виде текста или непосредственно в виде массива байт.
С помощью метода writeTo можно перенаправить массив байт в другой поток. Данный метод в качестве параметра принимает объект OutputStream, в который производится запись массива байт :
Для ByteArrayOutputStream не надо явным образом закрывать поток с помощью метода close.
Класс FileOutputStream
Класс FileOutputStream создаёт объект класса OutputStream, который можно использовать для записи байтов в файл. Это основной класс для работы с файлами. Создание нового объекта не зависит от того, существует ли заданный файл или нет. Если файл отсутствует, то будет создан новый файл. В случае попытки открытия файла, доступного только для чтения, будет вызвано исключение.
FileOutputStream имеет следующий конструкторы:
Смысл конструкторов последнего понятен из их описания. Но имеется несколько нюансов :
- При открытии файла на запись, если файл не существует, то он будет создан.
- Если файл существует, то он будет полностью обновлен. Т.е. если открыть и сразу закрыть файл, то содержимое файла будет уничтожено; реальный файл на диске станет нулевой длины.
- Исключением для предыдущего правила является последний из конструкторов. Если третьему параметру append присвоить значение true, то можно будет дописывать в конец файла.
Какой-либо дополнительной функциональности по сравнению с базовым классом FileOutputStream не добавляет.
Класс BufferedOutputStream
Класс BufferedOutputStream создает буфер для потоков вывода. Этот буфер накапливает выводимые байты без постоянного обращения к устройству. И когда буфер заполнен, производится запись данных.
Класс BufferedOutputStream в конструкторе принимает в качестве параметра объект OutputStream — в примере это файловый поток вывода FileOutputStream.
BufferedOutputStream не добавляет много новой функциональности, он просто оптимизирует действие потока выводаи его следует использовать для организации более эффективного буферизованного вывода в поток.
Класс DataOutputStream
Класс DataOutputStream позволяет писать данные в поток через интерфейс DataOutput, который определяет методы, преобразующие элементарные значения в форму последовательности байтов. Такие потоки облегчают сохранение в файле двоичных данных.
Для записи каждого из примитивных типов предназначен свой метод класса DataOutputStream:
- writeByte(int value) — записывает в поток 1 байт
- writeChar(int value) — записывает 2х-байтовое значение char
- writeInt(int value) — записывает в поток целочисленное значение int
- writeShort(int v) — записывает в поток значение short
- writeFloat(float value) — записывает в поток 4-байтовое значение float
- writeDouble(double value) — записывает в поток 8-байтовое значение double
- writeBoolean(boolean value) — записывает в поток булевое однобайтовое значение
- writeLong(long value) — записывает в поток значение long
- writeUTF(String value) — записывает в поток строку в кодировке UTF-8
Класс PrintStream
PrintStream является именно тем классом, который используется для вывода информации в консоль. Когда мы с помощью вызова System.out.println() пишем в консоль некоторую информацию, то тем самым используется PrintStream, так как переменная out класса System представляет объект класса PrintStream, а метод println() — это метод класса PrintStream.
Но PrintStream можно использовать для записи информации в поток вывода. Например, запишем информацию в файл:
В данном примере используется конструктор PrintStream, который в качестве параметра принимает поток вывода FileOutputStream. Можно было бы также использовать конструктор с указанием названия файла для записи: PrintStream (String filename).
С помощью метода println() производится запись информации в выходной поток — то есть в объект FileOutputStream. В случае с выводом на консоль с помощью System.out.println() в качестве потока вывода выступает консоль.
Для вывода информации в выходной поток PrintStream использует следующие методы:
Следующий код показывает возможности использования форматированного вывода класса PrintStream :
Класс ObjectOutputStream
Класс ObjectOutputStream используется для сериализации объектов в поток. Сериализация представляет процесс записи состояния объекта в поток, соответственно процесс извлечения или восстановления состояния объекта из потока называется десериализацией. Сериализация очень удобна, когда идет работа со сложными объектами.
Для создания объекта ObjectOutputStream необходимо в конструктор передать поток, в который будет производится запись объектов.
Для записи данных ObjectOutputStream использует ряд методов, среди которых можно выделить следующие:
Метод | Описание |
---|---|
void close() | закрывает поток |
void flush() | сбрасывает содержимое буфера в выходной поток и очищает его |
void write(byte[] buf) | записывает в поток массив байтов |
void write(int val) | записывает в поток один младший байт из val |
void writeBoolean(boolean val) | записывает в поток значение boolean |
void writeByte(int val) | записывает в поток один младший байт из val |
void writeChar(int val) | записывает в поток значение типа char, представленное целочисленным значением |
void writeDouble(double val) | записывает в поток значение типа double |
void writeFloat(float val) | записывает в поток значение типа float |
void writeInt(int val) | записывает целочисленное значение |
void writeLong(long val) | записывает значение типа long |
void writeShort(int val) | записывает значение типа short |
void writeUTF(String str) | записывает в поток строку в кодировке UTF-8 |
void writeObject(Object obj) | записывает в поток отдельный объект |
Представленные методы охватывают весь спектр данных, которые можно сериализовать.
Пример использования класса ObjectOutputStream :
Необходимо принимать во внимание, что сериализовать можно только те объекты, которые реализуют интерфейс Serializable.
Класс PipedOutputStream
Пакет java.io содержит класс PipedOutputStream, который может быть подключен к PipedInputStream, используемый для установления связи между двумя каналами. Данные в PipedOutputStream передаются в потоке Thread, который отправляет их в подключенный PipedInputStream, где данные также читаются, но в другом потоке.
То есть, класс PipedOutputStream предназначен для передачи информации между программами через каналы (pipes).
Наиболее часто используемые методы класса PipedOutputStream :
- void write(int b) — запись байта в канал
- void write(byte[] bytes, int off, int len) — запись определенного количества len байт начиная со смещения off массив bytes
- connect(PipedInputStream pis) — установление связи в каналом ввода pis
- close() — закрытие канала
- flush() — сброс данных в канал
Все методы класса могут вызвать исключение IOException.
Пример использования класса PipedOutputStream :
Источник