Как правильно записывать байты в файл 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: Возможно, у вас нет прав на запись (разрешение) на запись файла в этом месте. Попробуйте другое место.