Java - Запис във файл

1. Общ преглед

В този урок ще проучим различни начини за писане във файл с помощта на Java. Ние ще се възползват от BufferedWriter , PrintWriter , FileOutputStream , DataOutputStream , RandomAccessFile , FileChannel, и Java 7 Файлове полезност клас.

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

Този урок е част от поредицата за Java „Назад към основите“ тук на Baeldung.

2. Пишете с буфериран писател

Нека започнем просто и използваме BufferedWriter, за да напишем String в нов файл :

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, за да запишем двоични данни във файл.

Следният код преобразува String в байтове и записва байтовете във файл с помощта на 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, за да напишем String във файл:

@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 представя нов начин на работа с файловата система, заедно с нов клас полезност: Файлове .

Използвайки класа 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. Пишете във временен файл

Сега нека се опитаме да запишем във временен файл. Следният код създава временен файл и записва String към него:

@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. Заключете файла преди писане

И накрая, когато пишем във файл, понякога трябва да сме сигурни, че никой друг не пише в този файл едновременно. По принцип трябва да можем да заключим този файл, докато пишем.

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.