1. Información general
En este tutorial, exploraremos diferentes formas de escribir en un archivo usando Java. Usaremos BufferedWriter , PrintWriter , FileOutputStream , DataOutputStream , RandomAccessFile , FileChannel y la clase de utilidad Java 7 Files .
También veremos cómo bloquear el archivo mientras se escribe y discutiremos algunas conclusiones finales sobre cómo escribir en un archivo.
Este tutorial es parte de la serie Java "Back to Basics" aquí en Baeldung.
2. Escribir con BufferedWriter
Comencemos de manera simple y usemos BufferedWriter para escribir una cadena en un nuevo archivo :
public void whenWriteStringUsingBufferedWritter_thenCorrect() throws IOException { String str = "Hello"; BufferedWriter writer = new BufferedWriter(new FileWriter(fileName)); writer.write(str); writer.close(); }
La salida en el archivo será:
Hello
Luego podemos agregar una cadena al archivo existente :
@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(); }
El archivo será entonces:
Hello World
3. Escribir con PrintWriter
A continuación, veamos cómo podemos usar PrintWriter para escribir texto formateado en un archivo :
@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(); }
El archivo resultante contendrá:
Some String Product name is iPhone and its price is 1000$
Tenga en cuenta que no solo estamos escribiendo una cadena sin formato en un archivo, sino también un texto formateado con el método printf .
Podemos crear el escritor usando FileWriter , BufferedWriter o incluso System.out .
4. Escribir con FileOutputStream
Veamos ahora cómo podemos usar FileOutputStream para escribir datos binarios en un archivo.
El siguiente código convierte una cadena en bytes y escribe los bytes en un archivo usando 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(); }
La salida en el archivo será, por supuesto:
Hello
5. Escribir con DataOutputStream
A continuación, echemos un vistazo a cómo podemos usar DataOutputStream para escribir una cadena en un archivo:
@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. Escribir con RandomAccessFile
Ilustremos ahora cómo escribir y editar dentro de un archivo existente en lugar de simplemente escribir en un archivo completamente nuevo o agregar a uno existente. En pocas palabras: necesitamos acceso aleatorio.
RandomAccessFile nos permite escribir en una posición específica en el archivo dado el desplazamiento, desde el principio del archivo, en bytes.
Este código escribe un valor entero con un desplazamiento dado desde el principio del archivo:
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(); }
Si queremos leer el int almacenado en una ubicación específica , podemos usar este método:
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; }
Para probar nuestras funciones, escribamos un número entero, editámoslo y finalmente leamos:
@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. Escribir con FileChannel
Si se trata de archivos grandes, FileChannel puede ser más rápido que IO estándar. El siguiente código escribe String en un archivo usando 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. Clase Write With Files
Java 7 introduce una nueva forma de trabajar con el sistema de archivos, junto con una nueva clase de utilidad: Archivos .
Usando la clase Archivos , podemos crear, mover, copiar y eliminar archivos y directorios. También se puede utilizar para leer y escribir en un archivo:
@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. Escribir en un archivo temporal
Ahora intentemos escribir en un archivo temporal. El siguiente código crea un archivo temporal y le escribe una cadena :
@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(); }
Como podemos ver, es solo la creación del archivo temporal lo que es interesante y diferente. Después de ese punto, escribir en el archivo es lo mismo.
10. Bloquear archivo antes de escribir
Finalmente, al escribir en un archivo, a veces necesitamos asegurarnos de que nadie más esté escribiendo en ese archivo al mismo tiempo. Básicamente, necesitamos poder bloquear ese archivo mientras se escribe.
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.
La implementación de todos estos ejemplos y fragmentos de código se puede encontrar en GitHub.