Рубрики
Без рубрики

Java – Запись в файл

Множество способов записи данных в файл с помощью Java.

Автор оригинала: Eugen Paraschiv.

1. Обзор

В этом уроке мы рассмотрим различные способы записи в файл с помощью Java. Мы будем использовать BufferedWriter , PrintWriter , FileOutputStream , DataOutputStream , RandomAccessFile , FileChannel, и класс утилиты Java 7 Files .

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

Этот учебник является частью серии Java “Назад к основам” здесь, на Baeldung.

Дальнейшее чтение:

Java – Добавление данных в файл

Исключение FileNotFoundException в Java

Как скопировать файл с помощью Java

2. Запись С Помощью BufferedWriter

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

public void whenWriteStringUsingBufferedWritter_thenCorrect() 
  throws IOException {
    String str = "Hello";
    BufferedWriter writer = new BufferedWriter(new FileWriter(fileName));
    writer.write(str);
    
    writer.close();
}

Вывод в файле будет:

Hello

Затем мы можем добавить Строку к существующему файлу :

@Test
public void whenAppendStringUsingBufferedWritter_thenOldContentShouldExistToo() 
  throws IOException {
    String str = "World";
    BufferedWriter writer = new BufferedWriter(new FileWriter(fileName, true));
    writer.append(' ');
    writer.append(str);
    
    writer.close();
}

Затем файл будет:

Hello World

3. Пишите С Помощью PrintWriter

Далее давайте посмотрим, как мы можем использовать PrintWriter для записи форматированного текста в файл :

@Test
public void givenWritingStringToFile_whenUsingPrintWriter_thenCorrect() 
  throws IOException {
    FileWriter fileWriter = new FileWriter(fileName);
    PrintWriter printWriter = new PrintWriter(fileWriter);
    printWriter.print("Some String");
    printWriter.printf("Product name is %s and its price is %d $", "iPhone", 1000);
    printWriter.close();
}

Полученный файл будет содержать:

Some String
Product name is iPhone and its price is 1000$

Обратите внимание, что мы записываем в файл не только необработанную строку , но и некоторый форматированный текст с помощью метода printf .

Мы можем создать запись с помощью FileWriter , BufferedWriter или даже System.out .

4. Запись С Помощью FileOutputStream

Теперь давайте посмотрим, как мы можем использовать FileOutputStream для записи двоичных данных в файл.

Следующий код преобразует Строку в байты и записывает байты в файл с помощью FileOutputStream :

@Test
public void givenWritingStringToFile_whenUsingFileOutputStream_thenCorrect() 
  throws IOException {
    String str = "Hello";
    FileOutputStream outputStream = new FileOutputStream(fileName);
    byte[] strToBytes = str.getBytes();
    outputStream.write(strToBytes);

    outputStream.close();
}

Вывод в файле, конечно, будет:

Hello

5. Запись С Помощью DataOutputStream

Далее давайте рассмотрим, как мы можем использовать DataOutputStream для записи Строки в файл:

@Test
public void givenWritingToFile_whenUsingDataOutputStream_thenCorrect() 
  throws IOException {
    String value = "Hello";
    FileOutputStream fos = new FileOutputStream(fileName);
    DataOutputStream outStream = new DataOutputStream(new BufferedOutputStream(fos));
    outStream.writeUTF(value);
    outStream.close();

    // verify the results
    String result;
    FileInputStream fis = new FileInputStream(fileName);
    DataInputStream reader = new DataInputStream(fis);
    result = reader.readUTF();
    reader.close();

    assertEquals(value, result);
}

6. Запись С Помощью RandomAccessFile

Давайте теперь проиллюстрируем, как писать и редактировать внутри существующего файла , а не просто записывать в совершенно новый файл или добавлять к существующему. Проще говоря: нам нужен произвольный доступ.

RandomAccessFile позволяет нам записывать в определенную позицию в файле с учетом смещения — от начала файла — в байтах.

Этот код записывает целочисленное значение со смещением, заданным с начала файла:

private void writeToPosition(String filename, int data, long position) 
  throws IOException {
    RandomAccessFile writer = new RandomAccessFile(filename, "rw");
    writer.seek(position);
    writer.writeInt(data);
    writer.close();
}

Если мы хотим прочитать int , хранящийся в определенном месте , мы можем использовать этот метод:

private int readFromPosition(String filename, long position) 
  throws IOException {
    int result = 0;
    RandomAccessFile reader = new RandomAccessFile(filename, "r");
    reader.seek(position);
    result = reader.readInt();
    reader.close();
    return result;
}

Чтобы проверить наши функции, давайте напишем целое число, отредактируем его и, наконец, прочитаем его обратно:

@Test
public void whenWritingToSpecificPositionInFile_thenCorrect() 
  throws IOException {
    int data1 = 2014;
    int data2 = 1500;
    
    writeToPosition(fileName, data1, 4);
    assertEquals(data1, readFromPosition(fileName, 4));
    
    writeToPosition(fileName2, data2, 4);
    assertEquals(data2, readFromPosition(fileName, 4));
}

7. Запись С Помощью FileChannel

Если мы имеем дело с большими файлами, FileChannel может быть быстрее, чем стандартный ввод-вывод. Следующий код записывает Строку в файл с помощью FileChannel :

@Test
public void givenWritingToFile_whenUsingFileChannel_thenCorrect() 
  throws IOException {
    RandomAccessFile stream = new RandomAccessFile(fileName, "rw");
    FileChannel channel = stream.getChannel();
    String value = "Hello";
    byte[] strBytes = value.getBytes();
    ByteBuffer buffer = ByteBuffer.allocate(strBytes.length);
    buffer.put(strBytes);
    buffer.flip();
    channel.write(buffer);
    stream.close();
    channel.close();

    // verify
    RandomAccessFile reader = new RandomAccessFile(fileName, "r");
    assertEquals(value, reader.readLine());
    reader.close();
}

8. Запись С Помощью Класса Files

Java 7 представляет новый способ работы с файловой системой, а также новый класс утилит: Files .

Используя класс Files , мы можем создавать, перемещать, копировать и удалять файлы и каталоги. Он также может использоваться для чтения и записи в файл:

@Test
public void givenUsingJava7_whenWritingToFile_thenCorrect() 
  throws IOException {
    String str = "Hello";

    Path path = Paths.get(fileName);
    byte[] strToBytes = str.getBytes();

    Files.write(path, strToBytes);

    String read = Files.readAllLines(path).get(0);
    assertEquals(str, read);
}

9. Запись во Временный файл

Теперь давайте попробуем записать во временный файл. Следующий код создает

@Test
public void whenWriteToTmpFile_thenCorrect() throws IOException {
    String toWrite = "Hello";
    File tmpFile = File.createTempFile("test", ".tmp");
    FileWriter writer = new FileWriter(tmpFile);
    writer.write(toWrite);
    writer.close();

    BufferedReader reader = new BufferedReader(new FileReader(tmpFile));
    assertEquals(toWrite, reader.readLine());
    reader.close();
}

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

10. Блокировка Файла Перед Записью

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

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

@Test
public void whenTryToLockFile_thenItShouldBeLocked() 
  throws IOException {
    RandomAccessFile stream = new RandomAccessFile(fileName, "rw");
    FileChannel channel = stream.getChannel();

    FileLock lock = null;
    try {
        lock = channel.tryLock();
    } catch (final OverlappingFileLockException e) {
        stream.close();
        channel.close();
    }
    stream.writeChars("test lock");
    lock.release();

    stream.close();
    channel.close();
}

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

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

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

  • Если мы попытаемся прочитать из файла, который не существует, будет выдано исключение FileNotFoundException .
  • Если мы попытаемся записать в файл, который не существует, файл будет создан первым, и никаких исключений не будет.
  • Очень важно закрыть поток после его использования, так как он не закрыт неявно, чтобы освободить любые ресурсы, связанные с ним.
  • В выходном потоке метод close() вызывает flush() перед высвобождением ресурсов, что заставляет все буферизованные байты записываться в поток.

Рассматривая общие методы использования, мы можем видеть, например, что PrintWriter используется для записи форматированного текста, FileOutputStream для записи двоичных данных, DataOutputStream для записи примитивных типов данных, RandomAccessFile для записи в определенную позицию и FileChannel для более быстрой записи в большие файлы. Некоторые API этих классов позволяют больше, но это хорошее место для начала.

12. Заключение

В этой статье проиллюстрировано множество вариантов записи данных в файл с помощью Java.

Реализацию всех этих примеров и фрагментов кода можно найти на GitHub .