Java - Tulis ke Fail

1. Gambaran keseluruhan

Dalam tutorial ini, kita akan meneroka pelbagai cara untuk menulis ke fail menggunakan Java. Kami akan menggunakan kelas utiliti BufferedWriter , PrintWriter , FileOutputStream , DataOutputStream , RandomAccessFile , FileChannel, dan Java 7 Files .

Kami juga akan melihat mengunci fail semasa menulis dan membincangkan beberapa keputusan akhir semasa menulis ke fail.

Tutorial ini adalah sebahagian daripada siri "Kembali ke Asas" Java di Baeldung.

2. Tulis Dengan BufferedWriter

Mari mulakan ringkas dan gunakan BufferedWriter untuk menulis String ke fail baru :

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

Keluaran dalam fail adalah:

Hello

Kami kemudian dapat menambahkan String ke fail yang ada :

@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(); }

Fail itu akan menjadi:

Hello World

3. Tulis Dengan PrintWriter

Seterusnya, mari kita lihat bagaimana kita dapat menggunakan PrintWriter untuk menulis teks berformat ke fail :

@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(); }

Fail yang dihasilkan akan mengandungi:

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

Perhatikan bagaimana kita tidak hanya menulis String mentah ke fail, tetapi juga beberapa teks berformat dengan kaedah printf .

Kita boleh membuat penulis menggunakan FileWriter , BufferedWriter , atau bahkan System.out .

4. Tulis Dengan FileOutputStream

Sekarang mari kita lihat bagaimana kita dapat menggunakan FileOutputStream untuk menulis data binari ke fail.

Kod berikut mengubah String menjadi bait dan menulis byte ke fail menggunakan 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(); }

Keluaran dalam fail tentu saja:

Hello

5. Tulis Dengan DataOutputStream

Seterusnya, mari kita lihat bagaimana kita dapat menggunakan DataOutputStream untuk menulis String ke fail:

@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. Tulis Dengan RandomAccessFile

Sekarang mari kita gambarkan bagaimana menulis dan mengedit di dalam fail yang ada daripada hanya menulis ke fail yang sama sekali baru atau melampirkan ke fail yang ada. Ringkasnya: Kami memerlukan akses secara rawak.

RandomAccessFile membolehkan kita menulis pada kedudukan tertentu dalam fail yang diberi offset - dari awal fail - dalam bait.

Kod ini menulis nilai integer dengan ofset diberikan dari awal fail:

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(); }

Sekiranya kita ingin membaca int yang tersimpan di lokasi tertentu , kita boleh menggunakan kaedah ini:

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; }

Untuk menguji fungsi kami, mari tulis bilangan bulat, edit dan akhirnya baca semula:

@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. Tulis Dengan FileChannel

Sekiranya kita berurusan dengan fail besar, FileChannel dapat lebih cepat daripada IO standard. Kod berikut menulis String ke fail menggunakan 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. Tulis Dengan Kelas Fail

Java 7 memperkenalkan cara baru untuk bekerja dengan sistem fail, bersama dengan kelas utiliti baru: Files .

Dengan menggunakan kelas Files , kita dapat membuat, memindahkan, menyalin, dan menghapus fail dan direktori. Ia juga dapat digunakan untuk membaca dan menulis ke fail:

@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. Tulis ke Fail Sementara

Sekarang mari kita cuba menulis ke fail sementara. Kod berikut membuat fail sementara dan menulis String padanya:

@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(); }

Seperti yang dapat kita lihat, hanya penciptaan fail sementara yang menarik dan berbeza. Selepas itu, menulis ke fail adalah sama.

10. Kunci Fail Sebelum Menulis

Akhirnya, semasa menulis ke fail, kita kadang-kadang perlu memastikan bahawa tidak ada orang lain yang menulis ke fail itu pada masa yang sama. Pada dasarnya, kita perlu mengunci fail itu semasa menulis.

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.

Pelaksanaan semua contoh dan coretan kod ini boleh didapati di GitHub.