Автор оригинала: 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 .