Kwert-soft.ru

IT Софт для ПК
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Java io outputstream

Потоки вывода, 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 использует ряд методов, среди которых можно выделить следующие:

Читать еще:  Словарь на ошибки

Наиболее часто используемые методы класса PipedOutputStream :

  • void write(int b) — запись байта в канал
  • void write(byte[] bytes, int off, int len) — запись определенного количества len байт начиная со смещения off массив bytes
  • connect(PipedInputStream pis) — установление связи в каналом ввода pis
  • close() — закрытие канала
  • flush() — сброс данных в канал

Все методы класса могут вызвать исключение IOException.

Пример использования класса PipedOutputStream :

java.io.OutputStream Example

Posted by: Nikos Maravitsas in OutputStream April 15th, 2014 0 Views

In this example we are going to talk about OutputStream class in Java. OutputStream is an abstract class that enables you to write data to an output sink or destination. As with InputStream , that destination could be a console, a file, a socket, a pipe and even a buffer in memory. The most basic and fundamental thing you can do with an OutputStream is write a sequence of bytes to it.

1. Simple OutputStream Examples

In this section we are going to see how you can use OutputStream and it’s basic API methods to write bytes to a file. For this, Java offers a subclass of OutputStream that can be connected to a file destination. This is a FileOutputStream .

Let’s see how you can use it.

These are the basic three API methods that can write bytes to a destination resource, in this case a file :

  • void write(byte[] b) . Write all the bytes of byte array b in the destination resource
  • void write(byte[] b, int off, int len) . Write a sub sequence of the byte array
  • void write(int b) . Write a single byte

All these methods write a sequence of bytes in the destination resource (or a single byte). If one of these methods return successfully, then you are be able to read the bytes that you’ve written, from that resource. In the case of that resource being a file, it is not guaranteed that the bytes will be persisted in the physical device at which your file system runs on. On the contrary, in most cases they will be written in a system buffer. It’s the operating system’s and the hardware’s responsibility when and how to write those bytes in the psychical device. Of course, all of these happens for performance reasons.

It is also worth noting that most classes that extend OutputStream , provide their own, efficient implementation of the aforementioned OutpuStream ‘s fundamental methods.

1. Buffering an OutputStream

When you develop a very I/O intensive application that need to write large sequence of bytes in large files, then it’s highly advised that you should use some buffering. The basic idea of buffering is that you will use an internal,intermediate buffer to append your bytes. This means that the system won’t have to call the underlying OS’s “ write ” method for every single byte, but instead operate in this sequence of byte. This can make a big difference in performance sensitive applications, as is reduces the amount of expensive I/O operations.

To do this, Java offers a wrapper class, BufferedOutputStream . Let’s see how you can use it.

As you can see there’s not much that is different. Notice that I can choose the size of the aforementioned internal buffer, in this case 1024 bytes. If you don’t provide that second argument to the BufferedOutputStream constructor, the default buffer of 512 bytes will be used (which is sufficient in most cases).

OutputStream also offers a flush() method. What this does is to force any buffered output bytes to be written out to the target resource. In our case that resource is a file. Again when those buffered bytes are flushed, ti does not necessarily mean that they will be written in the physical disk.

2. Writing characters

Java also offers some convenient classes that bridge an byte stream to a character stream. In the case of OutputStream this class is OutputStreamWriter . Using this, you can directly write characters or Strings without having to obtain a byte array out of them. You can also specify the character set that you want your characters to be encoded to, or else the default will be used.

And of course there is a buffered version of OutputStreamWriter , named BufferedWriter . Let’s see how you can use it:

Besides buffering, which is the main reason why you should use BufferedWriter , it offers a newLine() methods, that uses the platform’s new line character in order to append it to your output. This will enable you to change line when writing in text files. Of course flush() method is also available here.

Another convenient class when working with character streams is PrintWriter class. It offers several methods like println , print and printf to customize the character stream output the way you want.

There is also a more convenient way to create a PrintWriter to a file, if you absolutely have to :

2. Writing to memory buffers

You can use a ByteArrayOutputStream to write raw bytes an an in memory byte array.

This will output :

2. Obtain an OutputStream using NIO

You can use the Files NIO class to obtain an OutputStream to a file.

Java io outputstream

Начиная разговор о потоках ввода-вывода, в первую очередь я бы хотел, чтобы вы увидели главную задачу — программа должна иметь возможность передать данные кому-то еще. Еще раз — современная программа не существует в вакууме, в сегодняшних условиях подавляющее большинство программ требует интеграции с другими. Интеграция всегда подразумевает передачу данных. Т.е. одна программа как-то передает данные в другую.
Нам, как программистам,. нужен некий механизм ПЕРЕДАЧИ данных.

Дальше уже идет специализация — каким образом это можно сделать. На сегодня основных вариантов три:

  1. Файловая система — одна программа записывает в файл и другая программа читает данные из файла
  2. Сетевое взаимодействие — две программы используют сеть для передачи данных друг другу
  3. Передача из одной области памяти в другую. Данный вариант достаточно часто используется в рамках одной программы, но это не обязательно

Конечно же есть внешние устройства, которые подключаются, например, по USB, COM-порту или как-то еще. И для них тоже требуется передача данных. Хотя нередко для таких устройств операционная система может предложить некое подобие работы с файловой системой.

Сосредоточимся на передаче данных. Что это с технической точки зрения ? Да очень просто — надо “переслать” некое количество байт. Т.е одна программа (отправитель), используя какой-то механизм, “отправляет” байты, а другая (потребитель), используя тот же механизм, “потребляет” эти байты. Причем логично, что байты идут друг за другом от отправителя к потребителю … в виде некоего ПОТОКА байтов.

Это конечно же исключительно мои догадки, но мне кажется, что разработчики Java думали как-то так, когда создавали библиотеку для передачи данных. Основой для них стало понятие ПОТОКА данных.

Причем, что на мой взгляд, важно отметить — ПОТОК данных предполагает, что среда переноса данных может быть разная. Это файловая система, по сути контроллер жесткого диска. Или это сетевая карта, в которую (или из которой) записываются (читаются) байты. Во всех случаях, по сути, вы должны записать/считать байт по определенному адресу. Дальше в дело вступает электроника — вы записали байт по адресу, контроллер той же сетевой карты отправит это байт в сеть, где контроллер сетевой карты на другом компьютере поместит этот байт по определенному адресу, который будет доступен для чтения.

Читать еще:  Char array to string java

Таким образом можно рассматривать механизм потоков, как инструмент. С помощью которого вы как-бы подключаетесь к источнику данных (в случае чтения) или приемнику данных (в случае записи) и после подключения вам просто надо либо читать оттуда, либо писать.туда.
Мне почему-то всегды было удобно видеть это как некоторую “трубу”, с одной стороны которой мой код, а с другой стороны все, что может принимать (или порождать) набор байтов. Я просто “заливаю” в эту трубу байты. А как они там на другом конце трубы попадают в приемник — не мое дело. Я просто использую “трубы” под каждый вид приемника — для файла, для сети.

Еще крайне интересным моментов является возможность “соединять” разные потоки. Чуть позже мы увидим практическое воплощение этой идеи.
Если создать образное представление, то вы можете использовать трубу, которая например окрашивает воду, которая проходит через нее, в другой цвет. Или фильтрует. Или насыщает какими-то добавками. И на конец этой трубы вы “прикрепляете” трубу в другими возможностями. Вода (или байты) проходя по этим трубам, трансформируется.
Если смогли представить, то будет здОрово, если не получается — ничего страшного. Надеюсь, что дальнейшие примеры позволят вам это увидеть.

Типы потоков

По направлению движения данных потоки можно разделить на две группы:

  1. Поток ввода (Input) — данные поступают из потока в нашу программу. Мы их читаем из этого потока
  2. Поток вывода (Output) — данные поступают в поток из нашей программы. Мы их пишем в этот поток

Вторым критерием разделения может служить ТИП передаваемых данных. Да-да, байты не всегда являются удобным вариантом передачи — есть еще текст. Символы. Я надеюсь, вы помните, что символ в Java занимает ДВА байта. Так вот передача двух байтов как одного целого числа имеет сложность — какой байт должен идти первым ? Есть такая неприятная ситуация — в разных операционных системах этот вопрос решается по-разному.- вы можете поискать информацию в Интернете на тему big endian little endian и узнать, как непросто бывает подружить Windows и Linux или просто Linux на разных компьютерах. В данной статье я не ставлю такой задачи — просто констатирую факт: передача символов длиной в два байта требует дополнительных усилий. Поэтому и появилось такое разделение:

В итоге мы получаем 4 типа потоков. Для каждого из этих типов Java предлагает отдельный базовый абстрактный класс. Почему абстрактный ? Потому, что у нас есть специализация — файлы, сеть, память. И расширяя базовый класс специальный класс решает свои специальные задачи. Но базовые функции для всех одинаковые. Что удобно — все специальные потоки по своей сути одно и тоже. Это дает гибкость и универсальность. Вот эти классы:

  1. InputStream — поток для чтения байтов (поток ввода)
  2. Reader — поток для чтения символов (поток ввода)
  3. OutputStream — поток для записи байтов (поток вывода)
  4. Writer — поток для записи символов (поток вывода)

Основной функцией для потоков ввода является метод read в нескольких модификациях, которые мы рассмотрим позже. Разница для InputStream и Reader состоит только в том, что первый читает байты (byte), а второй — символы (char).
Вполне логично вытекает название основного метода для классов OutputStream и Writer — метод write. Тоже в нескольких модификациях.

Основные действия с потоком

Схема работы с потоком в упрощенном виде выглядит так:

  1. Создается экземпляр потока
  2. Поток открывается (для чтения или записи)
  3. Производится чтение из потока/запись в поток
  4. Поток закрывается

Первые два пункта часто совмещены в рамках одного действия. По сути потоки можно представить как трубу, в которую “заливаются” байты или символы. Причем что еще интереснее, эти трубы можно “склеивать” друг с другом. Т.е один поток может передавать данные в другой, предварительно как-то их модифицируя.
Этот прием мы еще увидим, а пока давайте решим простую задачу — запишем строку в файл. В текстовый файл. Т.е. Нам потребуется поток для символов — Writer. Потом мы прочитаем этот файл — и для этого используем Reader.
Чуть выше я говорил, что Reader и Writer — абстрактные классы. Для работы с файлами нам потребуются уже конкретные и это будут FileReader и FileWriter.
Первым шагом мы запишем текст в файл. Порядок работы с потоком я в принципе описал, поэтому давайте конкретизируем наши действия. Создание и открытие файлового потока на запись делает в момент создания экземпляра объекта FileWriter, у которого конструктор принимает в качестве параметра строку с именем файла. Далее в цикле мы пишем в поток символы из строки и потом закрываем наш поток. Обратите внимание на конструкцию блока try. Мы уже встречали такое в разделе JDBC — групповые операции.
Повторю его идею — в момент начала блока try .. catch вы можете открыть ресурс (важно, чтобы он реализовывал интерфейс AutoCloseable). В таком случае по окончании блока ресурс будет автоматически закрыт и вам не надо вызывать метод close. Блок try .. catch мы должны использовать, т.к. Операции по открытию и записи в файл могут порождать исключения FileNotFoundException и IOException. Исключение FileNotFoundException является подклассом IOException и в принципе нам нет необходимости обрабатывать его отдельно. Так что мы сократили все до IOException.
Также советую внимательно прочитать комментарии в коде — они объясняют многие моменты.
Перейдем от слов к делу — смотрим код нашего примера

Gu >Last modified: November 13, 2019

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

In the 9 years of running Baeldung, I’ve never, ever done a «sale».
But. we’ve also not been through anything like this pandemic either.
And, if making my courses more affordable for a while is going to help a company stay in business, or a developer land a new job, make rent or be able to provide for their family — then it’s well worth doing.
Effective immediately, all Baeldung courses are 33% off their normal prices!
You’ll find all three courses in the menu, above, or here.

1. Overview

In this tutorial, we’ll explore details about the Java class OutputStream. OutputStream is an abstract class. This serves as the superclass for all classes representing an output stream of bytes.

We’ll examine what do these words like “output” and “stream” mean in more details as we go along.

2. Brief Introduction to Java IO

OutputStream is part of the Java IO API which defines classes required to perform I/O operations in Java. These are all packaged in the java.io namespace. This is one of the core packages available in Java since version 1.0.

Starting Java 1.4, we also have Java NIO packaged in the namespace java.nio which enables non-blocking input and output operations. Our focus area for this article, however, is ObjectStream as part of Java IO.

Details related to Java IO and Java NIO can be found here.

2.1. Input and Output

Java IO basically provides a mechanism to read data from a source and write data to a destination. Input represents the source while output represents the destination here.

These sources and destinations can be anything from Files, Pipes to Network Connections.

Читать еще:  Создание игр на javascript книга

2.2. Streams

Java IO provides the concept of streams which basically represents a continuous flow of data. Streams can support many different types of data like bytes, characters, objects, etc.

Moreover, connection to a source or a destination is what a stream represents. They hence come as either InputStream or OutputStream respectively.

3. Interfaces of OutputStream

OutputStream implements a bunch of interfaces which provide some distinct character to its subclasses. Let’s go through them quickly.

3.1. Closeable

The interface Closeable provides a method called close() which handles closing a source or a destination of data. Every implementation of OutputStream must provide an implementation of this method. Here they can perform actions to release resources.

3.2. AutoCloseable

The interface AutoCloseable also provides a method called close() with similar behavior to the one in Closeable. In this case, however, the method close() is automatically called when exiting a try-with-resource block.

More details regarding try-with-resource can be found here.

3.3. Flushable

The interface Flushable provides a method called flush() which handles flushing data to a destination.

A particular implementation of OutputStream may choose to buffer previously written bytes to optimize, but a call to flush() makes it write to the destination immediately.

4. Methods in OutputStream

OutputStream has several methods which each implementing class has to implement for their respective data types.

These are apart from close() and flush() methods that it inherits from Closeable and Flushable interfaces.

4.1. write(int b)

We can use this method to write one specific byte to the OutputStream. Since the argument “int” comprises four bytes, as par the contract only the first low order byte is written and the remaining three high order bytes and ignored:

If we call this method with data as “Hello World!”, what we get as result is a file with the following text:

This, as we can see, is the seventh character of the string indexed sixth.

4.2. write(byte[] b, int off, int length)

This overloaded version of the write() method is there to write a sub-sequence of the byte array to the OutputStream.

It can write “length” number of bytes from the byte array as specified by the argument starting at an offset determined by “off” to the OutputStream:

If we now call this method with the same data as before, we get the following text in our output file:

This is the substring of our data starting at index five and comprising five characters.

4.3. write(byte[] b)

This is yet another overloaded version of the write() method which can write an entire byte array as specified by the argument to the OutputStream.

This has the same effect as a call to write(b, 0, b.lengh):

When we call this method now with the same data, we have the entire String in our output file:

5. Direct Sub >

Now we’ll discuss some of the direct known subclasses of OutputStream which individually represent a specific data type of which the OutputStream they define.

They define their own methods apart from implementing those inherited from OutputStream.

We won’t go into the details of these subclasses.

5.1. FileOutputStream

As the name suggests, a FileOutputStream is an OutputStream to write data to a File. FileOutputStream, like any other OutputStream, can write a stream of raw bytes.

We have already examined different methods in FileOutputStream as part of the last section.

5.2. ByteArrayOutputStream

ByteArrayOutputStream is an implementation of OutputStream that can write data into a byte array. The buffer keeps growing as ByteArrayOutputStream writes data to it.

We can keep the default initial size of the buffer as 32 bytes or set a specific size using one of the constructors available.

The important thing to note here is that the method close() has practically no effect. The other methods in ByteArrayOutputStream can be safely called even after close() has been called.

5.3. FilterOutputStream

OutputStream primarily writes a byte stream to a destination, but it can as well transform the data before doing so. FilterOutputStream represents superclass of all such classes which perform a specific data transformation. FilterOutputStream is always constructed with an existing OutputStream.

Some of the examples of FilterOutputStream are BufferedOutputStream, CheckedOutputStream, CipherOutputStream, DataOutputStream, DeflaterOutputStream, DigestOutputStream, InflaterOutputStream, PrintStream.

5.4. ObjectOutputStream

ObjectOutputStream can write primitive data types and graphs of Java objects to a destination. We can construct an ObjectOutputStream using an existing OutputStream to write to a specific destination like File.

Please note that it is necessary for objects to implement Serializable for ObjectOutputStream to write them to a destination. You can find more details on Java Serialization here.

5.5. PipedOutputStream

A PipedOutputStream is useful to create a communication pipe. PipedOutputStream can write data which a connected PipedInputStream can read.

PipedOutputStream features a constructor to connect it with a PipedInputStream. Alternatively, we can do this later by using a method provided in PipedOutputStream called connect().

6. OutputStream Buffering

Input and output operations typically involve relatively expensive operations like disk access, network activity, etc. Performing this often can make a program less efficient.

We have “buffered streams” of data in Java to handle these scenarios. BufferedOutputStream writes data to a buffer instead which is flushed to the destination less often, when the buffer gets full, or the method flush() is called.

BufferedOutputStream extends FilterOutputStream discussed earlier and wraps an existing OutputStream to write to a destination:

The critical point to note is that every call to write() for each data argument only writes to the buffer and does not result in a potentially expensive call to the File.

In the case above, if we call this method with data as “Hello”, “World!”, this will only result in data being written to the File when the code exits from the try-with-resources block which calls the method close() on the BufferedOutputStream.

This results in an output file with the following text:

7. Writing Text with OutputStreamWriter

A byte stream, as discussed earlier, represents raw data which may be a bunch of text characters. Now we can get the character array and perform the conversion to the byte array ourselves:

Java provides convenient classes to bridge this gap. For the case of OutputStream, this class is OutputStreamWriter. OutputStreamWriter wraps an OutputStream and can directly write characters to the desired destination.

We can also optionally provide the OutputStreamWriter with a character set for encoding:

Now as we can see, we do not have to perform the transformation of the character array to the byte array before using FileOutputStream. OutputStreamWriter does this conveniently for us.

Not surprisingly when we call the above method with data like “Hello World!”, this results into a file with text as:

8. Conclusion

In this article, we discussed the Java abstract class OutputStream. We went through the interfaces it implements and the methods it provides.

Then we discussed some of the sub-classes of OutputStream available in Java. We finally talked about buffering and character streams.

As always, the code for the examples is available over on GitHub.

Ссылка на основную публикацию
Adblock
detector