Java - Scrivi su file

1. Panoramica

In questo tutorial, esploreremo diversi modi per scrivere su un file utilizzando Java. Utilizzeremo BufferedWriter , PrintWriter , FileOutputStream , DataOutputStream , RandomAccessFile , FileChannel e la classe di utilità Java 7 Files .

Vedremo anche come bloccare il file durante la scrittura e discuteremo alcuni suggerimenti finali sulla scrittura su file.

Questo tutorial fa parte della serie Java "Back to Basics" qui su Baeldung.

2. Scrivere con BufferedWriter

Cominciamo in modo semplice e utilizziamo BufferedWriter per scrivere una stringa in un nuovo file :

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

L'output nel file sarà:

Hello

Possiamo quindi aggiungere una stringa al file esistente :

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

Il file sarà quindi:

Hello World

3. Scrivere con PrintWriter

Successivamente, vediamo come possiamo usare PrintWriter per scrivere testo formattato in un file :

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

Il file risultante conterrà:

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

Nota come non stiamo solo scrivendo una stringa non elaborata in un file, ma anche del testo formattato con il metodo printf .

Possiamo creare il writer utilizzando FileWriter , BufferedWriter o anche System.out .

4. Scrivi con FileOutputStream

Vediamo ora come possiamo usare FileOutputStream per scrivere dati binari in un file.

Il codice seguente converte una stringa in byte e scrive i byte in un file utilizzando 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(); }

L'output nel file sarà ovviamente:

Hello

5. Scrivi con DataOutputStream

Successivamente, diamo un'occhiata a come possiamo usare DataOutputStream per scrivere una stringa in un file:

@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. Scrivere con RandomAccessFile

Illustriamo ora come scrivere e modificare all'interno di un file esistente piuttosto che scrivere semplicemente su un file completamente nuovo o aggiungerlo a uno esistente. In poche parole: abbiamo bisogno di un accesso casuale.

RandomAccessFile ci permette di scrivere in una posizione specifica nel file dato l'offset - dall'inizio del file - in byte.

Questo codice scrive un valore intero con offset dato dall'inizio del file:

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

Se vogliamo leggere l' int memorizzato in una posizione specifica , possiamo utilizzare questo metodo:

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

Per testare le nostre funzioni, scriviamo un numero intero, lo modifichiamo e infine lo rileggiamo:

@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. Scrivi con FileChannel

Se abbiamo a che fare con file di grandi dimensioni, FileChannel può essere più veloce dell'IO standard. Il codice seguente scrive String in un file utilizzando 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. Classe Scrivi con file

Java 7 introduce un nuovo modo di lavorare con il filesystem, insieme a una nuova classe di utilità: File .

Utilizzando la classe Files , possiamo creare, spostare, copiare ed eliminare file e directory. Può anche essere utilizzato per leggere e scrivere su un 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. Scrivere su un file temporaneo

Ora proviamo a scrivere su un file temporaneo. Il codice seguente crea un file temporaneo e vi scrive una stringa :

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

Come possiamo vedere, è solo la creazione del file temporaneo che è interessante e diverso. Dopo quel punto, la scrittura sul file è la stessa.

10. Blocca file prima di scrivere

Infine, quando scriviamo su un file, a volte dobbiamo assicurarci che nessun altro stia scrivendo su quel file contemporaneamente. Fondamentalmente, dobbiamo essere in grado di bloccare quel file durante la scrittura.

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.

L'implementazione di tutti questi esempi e frammenti di codice può essere trovata su GitHub.