Перейти к содержимому

Как правильно записывать байты в файл java

  • автор:

Как правильно записывать байты в файл java

Класс FileOutputStream предназначен для записи байтов в файл. Он является производным от класса OutputStream, поэтому наследует всю его функциональность.

Через конструктор класса FileOutputStream задается файл, в который производится запись. Класс поддерживает несколько конструкторов:

FileOutputStream(String filePath) FileOutputStream(File fileObj) FileOutputStream(String filePath, boolean append) FileOutputStream(File fileObj, boolean append)

Файл задается либо через строковый путь, либо через объект File. Второй параметр — append задает способ записи: eсли он равен true, то данные дозаписываются в конец файла, а при false — файл полностью перезаписывается

Например, запишем в файл строку:

import java.io.*; public class Program < public static void main(String[] args) < String text = "Hello world!"; // строка для записи try(FileOutputStream fos=new FileOutputStream("notes.txt")) < // перевод строки в байты byte[] buffer = text.getBytes(); fos.write(buffer, 0, buffer.length); System.out.println("The file has been written"); >catch(IOException ex) < System.out.println(ex.getMessage()); >> >

Для создания объекта FileOutputStream используется конструктор, принимающий в качестве параметра путь к файлу для записи. Если такого файла нет, то он автоматически создается при записи. Так как здесь записываем строку, то ее надо сначала перевести в массив байтов. И с помощью метода write строка записывается в файл.

Для автоматического закрытия файла и освобождения ресурса объект FileOutputStream создается с помощью конструктции try. catch.

При этом необязательно записывать весь массив байтов. Используя перегрузку метода write() , можно записать и одиночный байт:

fos.write(buffer[0]); // запись первого байта

Чтение файлов и класс FileInputStream

Для считывания данных из файла предназначен класс FileInputStream , который является наследником класса InputStream и поэтому реализует все его методы.

Для создания объекта FileInputStream мы можем использовать ряд конструкторов. Наиболее используемая версия конструктора в качестве параметра принимает путь к считываемому файлу:

FileInputStream(String fileName) throws FileNotFoundException

Если файл не может быть открыт, например, по указанному пути такого файла не существует, то генерируется исключение FileNotFoundException .

Считаем данные из ранее записанного файла и выведем на консоль:

import java.io.*; public class Program < public static void main(String[] args) < try(FileInputStream fin=new FileInputStream("notes.txt")) < int i; while((i=fin.read())!=-1)< System.out.print((char)i); >> catch(IOException ex) < System.out.println(ex.getMessage()); >> >

В данном случае мы считываем каждый отдельный байт в переменную i:

while((i=fin.read())!=-1)

Когда в потоке больше нет данных для чтения, метод возвращает число -1.

Затем каждый считанный байт конвертируется в объект типа char и выводится на консоль.

Подобным образом можно считать данные в массив байтов и затем производить с ним манипуляции:

import java.io.*; public class Program < public static void main(String[] args) < try(FileInputStream fin=new FileInputStream("notes.txt")) < byte[] buffer = new byte[256]; System.out.println("File data:"); int count; while((count=fin.read(buffer))!=-1)< for(int i=0; i> > catch(IOException ex) < System.out.println(ex.getMessage()); >> >

В данном случае с помощью метода read() считываем данные в массив buffer длиной 256 байтов. Метод возвращает количество считанных байтов.

Поскольк файл может быть больше 256 байтов, то считываем в цикле while до конца файла. Когда больше не останется файлов для считывания, то метод возвратит -1.

while((count=fin.read(buffer))!=-1)

Поскольку количество считанных байтов/размер файла могут быть меньше 256 байт, то реальное количество считанных байт сохраняем в переменную count. Затем выводим считанное количество данных на консоль в цикле for.

for(int i=0; i

Совместим оба класса и выполним чтение из одного и запись в другой файл:

import java.io.*; public class Program < public static void main(String[] args) < try(FileInputStream fin=new FileInputStream("notes.txt"); FileOutputStream fos=new FileOutputStream("notes_new.txt")) < byte[] buffer = new byte[256]; int count; // считываем буфер while((count=fin.read(buffer))!=-1)< // записываем из буфера в файл fos.write(buffer, 0, count); >System.out.println("File has been written"); > catch(IOException ex) < System.out.println(ex.getMessage()); >> >

Классы FileInputStream и FileOutputStream предназначены прежде всего для записи двоичных файлов, то есть для записи и чтения байтов. И хотя они также могут использоваться для работы с текстовыми файлами, но все же для этой задачи больше подходят другие классы.

Запись byte[] в файл на Java

В этом кратком руководстве мы изучим несколько различных способов записи массива байтов Java в файл. Мы начнем с самого начала, используя пакет Java IO. Далее мы рассмотрим пример с использованием Java NIO. После этого мы будем использовать Google Guava и Apache Commons IO.

2. Java ввод/вывод​

Пакет Java IO существует со времен JDK 1.0 и предоставляет набор классов и интерфейсов для чтения и записи данных.

Давайте используем FileOutputStream для записи изображения в файл:

 File outputFile = tempFolder.newFile("outputFile.jpg");   try (FileOutputStream outputStream = new FileOutputStream(outputFile))    outputStream.write(dataForWriting);   > 

Мы открываем выходной поток в наш целевой файл, а затем мы можем просто передать наш byte[] dataForWriting в метод записи . Обратите внимание, что здесь мы используем блок try -with-resources , чтобы убедиться, что мы закрываем OutputStream в случае возникновения исключения IOException .

3. Java НИО​

Пакет Java NIO был представлен в Java 1.4, а API файловой системы для NIO был представлен как расширение в Java 7. Java NIO использует буферизацию и не блокирует, тогда как Java IO использует блокирующие потоки. Синтаксис создания файловых ресурсов более краток в пакете java.nio.file .

Мы можем написать наш byte[] в одну строку, используя класс Files :

 Files.write(outputFile.toPath(), dataForWriting); 

В нашем примере либо создается файл, либо усекается существующий файл и открывается для записи. Мы также можем использовать Paths.get("путь/к/файлу") или Paths.get("путь", "к", "файл") для создания пути , который описывает, где будет храниться наш файл. Путь — это собственный способ выражения путей в Java NIO.

Если нам нужно переопределить поведение при открытии файла, мы также можем предоставить OpenOption методу записи .

4. Google Гуава​

Guava — это библиотека от Google, которая предоставляет множество типов для выполнения общих операций в Java, включая ввод-вывод.

Давайте импортируем Guava в наш файл pom.xml :

 dependency>   groupId>com.google.guavagroupId>   artifactId>guavaartifactId>   version>31.0.1-jreversion>   dependency> 

4.1. Файлы гуавы​

Как и в случае с пакетом Java NIO, мы можем записать наш byte[] в одну строку:

 Files.write(dataForWriting, outputFile); 

Метод Guava Files.write также принимает необязательный OptionOptions и использует те же значения по умолчанию, что и java.nio.Files.write .

Однако здесь есть одна загвоздка: метод Guava Files.write помечен аннотацией @Beta . Согласно документации , это означает, что он может измениться в любое время, поэтому его не рекомендуется использовать в библиотеках.

Итак, если мы пишем проект библиотеки, мы должны рассмотреть возможность использования ByteSink .

4.2. БайтСинк ​

Мы также можем создать ByteSink для записи нашего byte[] :

 ByteSink byteSink = Files.asByteSink(outputFile);  byteSink.write(dataForWriting); 

ByteSink — это место назначения, в которое мы можем записывать байты. Он поставляет OutputStream в пункт назначения.

Если нам нужно использовать java.nio.files.Path или предоставить специальный OpenOption , мы можем получить наш ByteSink с помощью класса MoreFiles :

 ByteSink byteSink = MoreFiles.asByteSink(outputFile.toPath(),   StandardOpenOption.CREATE,   StandardOpenOption.WRITE);  byteSink.write(dataForWriting); 

5. Apache Commons IO​

Apache Commons IO предоставляет некоторые общие файловые задачи.

Давайте импортируем последнюю версию commons-io :

 dependency>   groupId>commons-iogroupId>   artifactId>commons-ioartifactId>   version>2.11.0version>   dependency> 

Теперь давайте напишем наш byte[] с помощью класса FileUtils :

 FileUtils.writeByteArrayToFile(outputFile, dataForWriting); 

Метод FileUtils.writeByteArrayToFile похож на другие методы, которые мы использовали, в том, что мы даем ему файл , представляющий желаемое место назначения, и двоичные данные, которые мы записываем. Если наш целевой файл или любой из родительских каталогов не существует, они будут созданы.

6. Заключение​

В этом коротком руководстве мы узнали, как записывать двоичные данные из byte[] в файл, используя обычную Java и две популярные служебные библиотеки Java: Google Guava и Apache Commons IO.

Как всегда, код примера доступен на GitHub .

  • 1. Обзор
  • 2. Java ввод/вывод
  • 3. Java НИО
  • 4. Google Гуава
    • 4.1. Файлы гуавы
    • 4.2. БайтСинк

    Чтение и запись файлов

    В Java есть четыре основных абстрактных класса, реализующих потоки ввода-вывода: InputStream, OutputStream, Reader, Writer. Первые два работают с байтами, вторые – с символами.

    Для работы с файлами от этих абстрактных классов созданы соответственно классы FileInputStream, FileOutputStream, FileReader, FileWriter. Они являются адаптерами для объектов класса File к "интерфейсам" InputStream, OutputStream, Reader, Writer, т. е. к их методам.

    Скажем несколько слов об адаптере как паттерне, или шаблоне, проектирования. Класс-адаптер A наследуется от интерфейса B, к которому приспосабливается объект другого класса – C. Класс-адаптер A имеет поле типа класса объекта C.

    Например, объект File адаптируется к потоку ввода InputStream, т. е. все, что мы хотим получить из File, в конечном итоге мы будем получать из InputStream. Фактически мы работаем с InputStream, через адаптер FileInputStream, который с одной стороны наследуется от InputStream, а с другой – имеет поле, которому присваивается объект File.

    Адаптер выполняет работу по получению данных из файла и адаптации их к тому виду, который можно передать в методы InputStream. Класс-адаптер, в данном примере – FileInputStream, переопределяет методы InputStream, добавляя в них свой код.

    В основной ветке сначала создается объект, для которого требуется адаптер. Затем создается переменная класса, к которому выполняется адаптация. Этой переменной присваивается объект класса-адаптера, в конструктор которого передается адаптируемый объект.

    File file = new File("/home/user/pic.jpg"); InputStream fIn = new FileInputStream(file);

    Часто переменную определяют самим классом-адаптером:

    FileInputStream fIn = new FileInputStream(file);

    В конструктор можно передать строку-адрес. Объект File будет создан внутри адаптера. Пример побайтового копирования файла:

    import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class InputOutputStream  public static void main(String[] args) throws IOException  FileInputStream fileIn = new FileInputStream( "src/file/pets.png"); FileOutputStream fileOut = new FileOutputStream( "src/file/pets2.png"); while (fileIn.available() > 0)  int oneByte = fileIn.read(); fileOut.write(oneByte); > fileIn.close(); fileOut.close(); > >

    Если используются относительные адреса, они должны начинаться от корня проекта.

    В конструктор FileOutputStream можно также передать второй аргумент true. В этом случае, если файл существует, данные в него будут добавляться. Перезаписи файла не произойдет.

    Метод available() объекта класса FileInputStream возвращает количество непрочитанных байтов. Метод read() читает один байт и расширяет его до типа int. Кроме этого, есть другой метод read(), читающий массив байт в переменную-аргумент и возвращающий количество реально прочитанных байт. Метод write() также позволяет записывать блоками.

    byte[] blockBytes = new byte[100]; while (fileIn.available() > 0)  int qtyBytes = fileIn.read(blockBytes); fileOut.write(blockBytes, 0, qtyBytes); >

    При чтении конца файла блок может содержать меньше прочитанных байт, чем размерность массива. Поэтому write() позволяет указывать срез массива.

    У объектов FileOutputStream имеется метод flush(), который принудительно записывает находящиеся в буфере байты на диск. При вызове close() это происходит автоматически.

    С помощью класса PrintStream также можно создать поток вывода в файл. PrintStream является наследником FilterOutputStream, который в свою очередь наследник OutputStream как и FileOutputStream.

    import java.io.FileNotFoundException; import java.io.PrintStream; public class PrintStreamTest  public static void main(String[] args) throws FileNotFoundException  PrintStream fileOut = new PrintStream( "src/file/text.txt"); fileOut.println(10.5); fileOut.printf( "%s - %d - %f", "hi", 10, 1.1); fileOut.close(); > >

    Функция printf() предназначена для форматированного вывода.

    Заметим, переменная System.out является объектом типа PrintStream.

    В работе с вводом-выводом также используется другой паттерн проектирования – обертка (wrapper), он же декоратор (decorator). Декоратор расширяет функциональность объекта, а не приспосабливает объект к какому-либо стороннему интерфейсу.

    Поэтому класс-обертка наследуется от того же класса или интерфейса, что и оборачиваемый объект. В классе-обертке переопределяются методы оборачиваемого объекта. В методах обертки вызываются методы оборачиваемого класса и вводится дополнительная функциональность.

    В основной ветке создается объект оборачиваемого класса, который передается в конструктор обертки. Внутри класса-обертки есть поле типа декорируемого класса. Этому полю присваивается переданный объект.

    BufferedInputStream – класс-обертка для InputStream (наследует через FilterInputStream). В отличие от InputStream класс BufferedInputStream позволяет предварительно читать в буфер порции байт, что уменьшает количество обращений к файлу. Существует также BufferedOutputStream.

    import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; public class BufferStream  public static void main(String[] args) throws IOException  FileInputStream fileIn = new FileInputStream("src/file/text.txt"); BufferedInputStream bufIn = new BufferedInputStream(fileIn, 100); int i; while((i = bufIn.read())!= -1) System.out.print((char)i); > > >

    Конструктор класса BufferedInputStream принимает объект InputStream или его наследника.

    Хотя данные считываются блоками, метод read() извлекает их по одному. Однако в данном случае он будет извлекать их из буфера.

    С помощью классов FileReader и FileWriter выполняется ввод-вывод в текстовые файлы.

    FileReader reader = new FileReader( "src/file/text.txt"); FileWriter writer = new FileWriter( "src/file/text2.txt"); while (reader.ready())  int c = reader.read(); writer.write(c); > reader.close(); writer.close();

    Метод ready() возвращает истину, если остались непрочитанные символы.

    Читать и писать можно блоками. Также методу write() можно передать строку:

    FileReader reader = new FileReader( "src/file/text.txt"); FileWriter writer = new FileWriter( "src/file/text3.txt"); char[] buff = new char[10]; while (reader.ready())  int qtySymbols = reader.read(buff); writer.write(buff, 0, qtySymbols); > writer.write("Halo"); reader.close(); writer.close();

    Рассматривая ввод данных с клавиатуры, мы уже использовали класс BufferedReader, который наследуется от Reader и позволяет читать отдельные строки методом readLine(). Его также можно использовать для построчного чтения файлов:

    import java.io.*; public class BufferedReaderTest  public static void main(String[] args) throws IOException  Reader reader = new FileReader( "src/file/text.txt"); BufferedReader buffReader = new BufferedReader(reader); while (buffReader.ready())  System.out.println( buffReader.readLine()); > reader.close(); buffReader.close(); > >

    Существует и BufferedWriter.

    X Скрыть Наверх

    Программирование на Java. Курс

    Запись байта [] в файл в Java

    «Преобразовать массив байтов в объект File» не имеет никакого смысла, кроме как в том, что вы хотите записать байты в файл. У вас есть как минимум 3 разных ответа ниже, как это сделать. Это то, что вы после? В противном случае, пожалуйста, уточните.

    pap 26 июль 2011, в 11:14

    Я разрабатываю в Android . У меня есть файл, сохраненный на диске в зашифрованном виде и разблокировать шифрование, поэтому я получил массив байтов, поэтому я хочу преобразовать их в файл, чтобы показать файл PDF в программе просмотра PDF, но без сохранения файла на диске без шифрования

    farajnew 26 июль 2011, в 11:21

    Ну, тогда это совсем другое. Вы хотите запустить pdf-просмотрщик, по сути, из чего-то вроде MemoryFile ( developer.android.com/reference/android/os/MemoryFile.html ). Не уверен, как вы это сделаете, или как вы отображаете PDF. У вас есть код или информация, которую вы можете добавить о том, как вы на самом деле вызываете программу просмотра PDF? А какой просмотрщик вы используете?

    pap 26 июль 2011, в 12:17

    Пожалуйста, измените вопрос и название, чтобы отразить тот факт, что вы спрашиваете о чем-то связанном с PDF. Вопрос выглядит пока запутанным.

    Mike Keskinov 29 авг. 2012, в 16:22

    -1 Вопрос совершенно не связан с тем, что ты хочешь знать. Создайте новый вопрос и задайте вопрос «Как я могу рендерить PDF на Android из байтов в памяти?»

    Aaron Digulla 10 окт. 2012, в 13:25
    Показать ещё 3 комментария
    Поделиться:

    5 ответов

    Лучший ответ

    Объект File не содержит содержимого файла. Это только указатель на файл на вашем жестком диске (или другой носитель, например SSD, USB-накопитель, общий сетевой ресурс). Поэтому я думаю, что вы хотите записать его на жесткий диск.

    Вы должны записать файл, используя некоторые классы в Java API

    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(yourFile)); bos.write(fileBytes); bos.flush(); bos.close(); 

    Вы также можете использовать Writer вместо OutputStream. Использование записи позволит вам написать текст (String, char []).

    BufferedWriter bw = new BufferedWriter(new FileWriter(yourFile)); 

    Поскольку вы сказали, что хотите сохранить все в памяти и не хотите ничего писать, вы можете попробовать использовать ByteArrayInputStream . Это имитирует InputStream, который вы можете передать большинству классов.

    ByteArrayInputStream bais = new ByteArrayInputStream(yourBytes); 

    Martijn Courteaux 26 июль 2011, в 10:44
    Поделиться

    Файловый объект является нулевым? и я не хочу, чтобы что-либо было сохранено на диске . Это нормально, чтобы быть в памяти, так как конвертировать массив байтов в объект File

    farajnew 26 июль 2011, в 11:10

    Я получил это java.io.IOException: открытие не удалось: EACCES (Отказано в доступе) в приложении для Android при записи BufferedOutputStream bos = new BufferedOutputStream (new FileOutputStream (yourFile));

    Sanket Thakkar 02 авг. 2013, в 07:41

    @SanketThakkar: Возможно, у вас нет прав на запись (разрешение) на запись файла в этом месте. Попробуйте другое место.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *