Как правильно записывать байты в файл java
Перейти к содержимому

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

  • автор:

Запись 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. БайтСинк

    Как перевести файл в массив байтов

    Как перевести файл в массив байтов и наоборот? Файлом может быть MS Word и Excel или что-то другое. Также и строку.

    Отслеживать
    user177221
    задан 7 сен 2015 в 3:48
    Aslan Kussein Aslan Kussein
    1,776 2 2 золотых знака 14 14 серебряных знаков 35 35 бронзовых знаков

    3 ответа 3

    Сортировка: Сброс на вариант по умолчанию

    byte[] array = Files.readAllBytes(Paths.get(fileName)); 

    Отслеживать
    5,509 16 16 серебряных знаков 42 42 бронзовых знака
    ответ дан 7 сен 2015 в 7:33
    465 3 3 серебряных знака 13 13 бронзовых знаков

    byte[] fileInArray = new byte[(int)file.length()]; FileInputStream f = new FileInputStream(""); f.read(fileInArray); 

    Это без использования всякого рода сторонних библиотек. Средствами java.

    Отслеживать
    ответ дан 7 сен 2015 в 4:18
    Виталий Вихляев Виталий Вихляев
    891 15 15 серебряных знаков 34 34 бронзовых знака

    \я вот если я пытаюсь из джава класса сделать массив байтов и какой метод мне использовать не знаете?

    7 сен 2015 в 4:28

    @Aslan Kussein с файлами .java точно так же. Если же вам нужно в массив байтов преобразовать объект какого-то класса , то вам необходимо его сериализовать. Очень хороший ресурс на эту тему здесь

    7 сен 2015 в 4:56

    А вы документацию к InputStream.read читали? Там вообще-то написано «Reads some number of bytes from the input stream and stores them into the buffer array b». А вы даже возвращаемое значение не проверяете. Чтение может прерваться в произвольный момент, и вы никак не узнаете, сколько байт считано по факту.

    7 сен 2015 в 6:20

    @Tagir Valeev никто не мешает обработать ошибку при чтении. Насчет контроля количества считанных байт согласен- в моем способе его нет (а может и не нужен). И все же. Как вы решали бы эту проблему, при использовании java более взрослых версий?

    7 сен 2015 в 7:10

    Вообще, вероятно, лучше memory-mapping сделать. Это будет быстрее. Если без мемори-мэппинга — воспользовался бы библиотекой или написал бы вручную примерно то же самое, что в readAllBytes .

    Выполнить чтение всех байтов с файла с помощью FileInputStream в массив байтов

    Выполнить чтение всех байтов с файла с помощью FileInputStream в массив байтов.

    Создать строку на основе прочитанного массива байтов и после этого выполнить String.trim().

    Разделить полученную строку таким образом, чтобы создать экземпляры классов(String.split).

    Так же, реализовать запись в файл в соответствующем формате.

    Вот мой массив и собственно запись —

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
    public static void main(String[] args) { Car[] taxiPark = new Car[]{ new Truck("Reno", 65000, 20, 180, 25000), new Truck("Scania", 100000, 15, 220, 30000), new MilitaryVehicles("T-34", 85000, 50, 35, 5), new MilitaryVehicles("T-190", 120000, 70, 60, 10), new PassengerCar("Lanos", 5000, 6, 225, 4), new PassengerCar("BMW", 10000, 9, 300, 5) }; try (final FileWriter writer = new FileWriter("Letter.txt", false)){ for (int i = 0; i  taxiPark.length; ++i) { final String s = taxiPark[i].toString(); writer.write(s); writer.write(System.lineSeparator()); System.out.println(s); } } catch(IOException e) { System.out.println(e.getMessage()); } }

    94731 / 64177 / 26122
    Регистрация: 12.04.2006
    Сообщений: 116,782
    Ответы с готовыми решениями:

    Чтение байтов из файла
    Здравсвуйте! Есть файл в котором записвны числа 1234567890. Есть такой код int amount, sum = 0; .

    Чтение группы байтов из файла
    Необходимо прочитать 4 байта из двоичного файла. Открываю файл и ставлю указатель в нужное место.

    Чтение и запись байтов из файла
    Подскажите пожалуйста каким образом магу прочесть .дат файл чтобы прочесть байты и обратно.

    Чтение байтов из бинарного файла
    Доброго времени суток. Столкнулся с задачкой которую не могу правильно решить. Вообщем к сути.

    746 / 493 / 285
    Регистрация: 10.09.2015
    Сообщений: 1,530

    Добавлено через 1 минуту
    и при чём тут машины?

    Добавлено через 7 минут
    покажи как файл у тебя записывается

    Добавлено через 49 секунд
    всёс виду выглядит очень просто

    Регистрация: 28.02.2019
    Сообщений: 11

    Смотри, у меня есть таксипарк, от него наследуются машины разных видов(каждый со своей особенностью), отдельно есть класс таксипарка, в котором выполняются определенные функции, вот в меине мне нужно записать этот массив в файл потом выполнить чтение всех байтов.
    Вот полное задание — Реализовать инициализацию массива Car’ов (из задания про таксопарк) на основе файла (машины должны храниться в файле).

    Запятая (,) — разделитель свойств машины

    Точка с запятой и конец строки (;\n\r) — разделитель машин

    Выполнить чтение всех байтов с файла с помощью FileInputStream в массив байтов.

    Создать строку на основе прочитанного массива байтов и после этого выполнить String.trim().

    Разделить полученную строку таким образом, чтобы создать экземпляры классов(String.split).

    Так же, реализовать запись в файл в соответствующем формате.

    746 / 493 / 285
    Регистрация: 10.09.2015
    Сообщений: 1,530

    toString() покажи, пжл

    Добавлено через 4 минуты
    в общем вот чтение файла:

    1 2 3 4 5 6 7 8 9 10 11
    private static String readFile(String path) { String result = null; try (FileInputStream in = new FileInputStream(new File(path))) { byte[] buffer = new byte[in.available()]; in.read(buffer, 0, buffer.length); result = new String(buffer); } catch (IOException e) { e.printStackTrace(); } return result; }

    Добавлено через 2 минуты
    коли ты записываешь строки через System.lineSeparator();

    то делишь потом текст из файла на строковое представление объекта

    String[] cars = string.split(System.lineSeparator()); //string — это то, что вернулось из метода чтения файла

    Регистрация: 28.02.2019
    Сообщений: 11

    Вот to.String Такси парка —
    public String toString() return «TaxiParkInter «taxiPark = » + Arrays.toString(taxiPark) +
    ‘>’;
    >

    А вот отдельной машины(to.String определен в каждом классе) —
    public String toString() return «MilitaryVehicles » Max Speed = » + getMaxSpeed() +
    » LevelOfDestruction = » + LevelOfDestruction +
    ‘>’;
    >

    746 / 493 / 285
    Регистрация: 10.09.2015
    Сообщений: 1,530

    затем, почитай про паттерн Factory. Он как раз для создания фабрик.
    у тебя там и танки и машины и т.д.
    вот и будешь передавать параметром в метод типа «tank», а он тебе возвращать объект типа tank

    Добавлено через 5 минут
    переделай метод toString() как просят записывать файл (через запятые)
    проще делить будет строку на поля объекта по запятой:

    1 2 3 4 5
    for (String car : string.split(System.lineSeparator()) { String[] values = car.split(","); //сделаешь метод, который принимает массив values и парсит его в объект //а затем в метод Factory.build(String type) передашь тип и поля и он тебе вернёт нужный класс }

    Добавлено через 4 минуты
    имя класса можно получить:

    this.getClass().getCanonicalName()

    Регистрация: 28.02.2019
    Сообщений: 11
    Спасибо, посижу поломаю голову, пока что правда не все понял=)) Но очень благодарен
    746 / 493 / 285
    Регистрация: 10.09.2015
    Сообщений: 1,530

    LexusJava, если не получится, завтра ближе к вечеру смогу помочь тебе. А сейчас, ксожалению, спать мне нужно. Если что пиши и удачи с кодом или до завтра

    Регистрация: 28.02.2019
    Сообщений: 11
    Большое спасибо, буду иметь ввиду, Доброй ночи
    Регистрация: 12.05.2019
    Сообщений: 201

    как ни странно но у меня тот же самый вопрос и написанное выше никак не помогло(((

    застряла на этапе «Разделить полученную строку таким образом, чтобы создать экземпляры классов(String.split).»

    вот что у меня есть

    Car[] cars = storage.readCars();
    1 2 3 4 5 6 7 8 9 10 11
    public Car[] readCars() throws IOException { FileInputStream fis = new FileInputStream(text.txt); byte[] readBytes = new byte[fis.available()]; fis.read(readBytes); String file = new String(readBytes); System.out.println(Arrays.toString(file.split(";\r\n"))); String[] fieldCar; fieldCar = file.split(","); fis.close(); return cars; /////// . }

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

    условие тоже самое что у топикстартера

    1021 / 561 / 185
    Регистрация: 18.08.2013
    Сообщений: 2,026
    Записей в блоге: 2
    Sma6nta, как выглядят конструкторы создаваемых объектов?
    Регистрация: 12.05.2019
    Сообщений: 201

    это хороший вопрос.
    я на него с утра пытаюсь ответить.

    были конструкторы. нормальные
    имя- стринг
    int
    int
    и т.п. гетеры сетеры.

    создавались обьекты
    car[0] = new MyCar(«Giguli», 12, 38, 25, 3);

    и отлично создавались. но теперь я пытаюсь считать с файла.
    А оно там когда из байтов преобразуется то все String

    я пыталась создать новый конструктор

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
    public class CarMaker implements Car{ private String mark; private String model; private String fuelConsumption; private String speed; private String price; private String typecar; public CarMaker(String mark, String model, String fuelConsumption, String speed, String price, String typecar) { this.mark = mark; this.model =model; this.fuelConsumption =fuelConsumption; this.speed = speed; this.price = price; this.typecar=typecar; } @Override public String getMark() { // TODO Auto-generated method stub return null; } @Override public void setMark() { // TODO Auto-generated method stub } @Override public int getModel() { // TODO Auto-generated method stub return 0; } @Override public void setModel() { // TODO Auto-generated method stub } @Override public int getFuelConsumption() { // TODO Auto-generated method stub return 0; } @Override public void setFuelConsumption() { // TODO Auto-generated method stub } @Override public int getSpeed() { // TODO Auto-generated method stub return 0; } @Override public void setSpeed() { // TODO Auto-generated method stub } @Override public int getPrice() { // TODO Auto-generated method stub return 0; } @Override public void setPrice() { // TODO Auto-generated method stub } @Override public String getTypeCar() { // TODO Auto-generated method stub return null; } @Override public void setTypeCar() { // TODO Auto-generated method stub } }

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

    В 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. Курс

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

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