1. Огляд
У цьому посібнику ми розглянемо різні способи запису у файл за допомогою Java. Ми використаємо BufferedWriter , PrintWriter , FileOutputStream , DataOutputStream , RandomAccessFile , FileChannel та клас утиліти Java 7 Files .
Ми також розглянемо блокування файлу під час написання та обговоримо деякі остаточні висновки щодо запису у файл.
Цей підручник є частиною серії "Назад до основ" Java на Baeldung.
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 може бути швидшим, ніж стандартний IO. Наступний код записує String у файл за допомогою 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. Пишіть за допомогою файлів класу
Java 7 introduces a new way of working with the filesystem, along with a new utility class: Files.
Using the Files class, we can create, move, copy, and delete files and directories. It can also be used to read and write to a file:
@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. Write to a Temporary File
Now let's try to write to a temporary file. The following code creates a temporary file and writes a String to it:
@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(); }
As we can see, it's just the creation of the temporary file that is interesting and different. After that point, writing to the file is the same.
10. Lock File Before Writing
Finally, when writing to a file, we sometimes need to make extra sure that no one else is writing to that file at the same time. Basically, we need to be able to lock that file while writing.
Let's make use of FileChannel to try locking the file before writing to it:
@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(); }
Note that if the file is already locked when we try to acquire the lock, an OverlappingFileLockException will be thrown.
11. Notes
After exploring so many methods of writing to a file, let's discuss some important notes:
- If we try to read from a file that doesn't exist, a FileNotFoundException will be thrown.
- If we try to write to a file that doesn't exist, the file will be created first and no exception will be thrown.
- It is very important to close the stream after using it, as it is not closed implicitly, to release any resources associated with it.
- In output stream, the close() method calls flush() before releasing the resources, which forces any buffered bytes to be written to the stream.
Looking at the common usage practices, we can see, for example, that PrintWriter is used to write formatted text, FileOutputStream to write binary data, DataOutputStream to write primitive data types, RandomAccessFile to write to a specific position, and FileChannel to write faster in larger files. Some of the APIs of these classes do allow more, but this is a good place to start.
12. Conclusion
This article illustrated the many options of writing data to a file using Java.
Реалізацію всіх цих прикладів та фрагментів коду можна знайти на GitHub.