Java - Gravar no arquivo
1. Visão geral
Neste tutorial, exploraremos diferentes maneiras dewrite to a file using Java. UsaremosBufferedWriter,PrintWriter,FileOutputStream,DataOutputStream,RandomAccessFile,FileChannele o Java 7Files classe de utilidade.
Também veremos como bloquear o arquivo durante a gravação e discutiremos algumas dicas finais sobre como gravar no arquivo.
Este artigo faz parte dethe “Java – Back to Basic” series aqui no exemplo.
Leitura adicional:
FileNotFoundException em Java
Um guia rápido e prático para FileNotFoundException em Java.
Como copiar um arquivo com Java
Veja algumas maneiras comuns de copiar arquivos em Java.
2. Escreva comBufferedWriter
Vamos começar simples - e usarBufferedWriter para escrever umStringto a new file:
public void whenWriteStringUsingBufferedWritter_thenCorrect()
throws IOException {
String str = "Hello";
BufferedWriter writer = new BufferedWriter(new FileWriter(fileName));
writer.write(str);
writer.close();
}
A saída no arquivo será:
Hello
Podemos entãoappend a String to the existing file:
@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();
}
O arquivo será então:
Hello World
3. Escreva comPrintWriter
A seguir - vamos ver como podemos usar umPrintWriter para gravar texto formatado em um arquivo:
@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();
}
O arquivo resultante conterá:
Some String
Product name is iPhone and its price is 1000$
Observe como não estamos apenas escrevendo uma string bruta no arquivo, mas também algum texto formatado com o métodoprintf.
Podemos criar o gravador usandoFileWriter,BufferedWriter ou mesmoSystem.out.
4. Escreva comFileOutputStream
Vamos agora ver como podemos usarFileOutputStream awrite binary data to a file. O código a seguir converte aString bytes internos e grava os bytes no arquivo usando umFileOutputStream:
@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();
}
A saída no arquivo será obviamente:
Hello
5. Escreva comDataOutputStream
A seguir - vamos dar uma olhada em como podemos usar umDataOutputStream para gravar uma String no arquivo:
@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. Escreva comRandomAccessFile
Vamos agora ilustrar como escrever e editar dentro de um arquivo existente - em vez de apenas gravar em um arquivo completamente novo ou anexar a um existente. Simplificando - precisamos de acesso aleatório.
RandomAccessFile nos permite escrever em uma posição específica no arquivo dado o deslocamento - desde o início do arquivo - em bytes. O código a seguir grava um valor inteiro com o deslocamento fornecido desde o início do arquivo:
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 quisermos ler o int armazenado em um local específico, podemos usar o seguinte 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 testar nossas funções, vamos escrever um inteiro - editá-lo - e, finalmente, lê-lo de volta:
@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. Escreva comFileChannel
Se você estiver lidando com arquivos grandes,FileChannel pode ser mais rápido que o IO padrão. O código a seguir gravaString em um arquivo usandoFileChannel:
@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. Escreva com a classeFiles
Java 7 apresenta uma nova maneira de trabalhar com o sistema de arquivos, junto com uma nova classe de utilitário -Files. Usando a classeFiles, podemos criar, mover, copiar, excluir arquivos e diretórios também; também pode ser usado para ler e gravar em um arquivo:
@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. Gravar em um arquivo temporário
Agora, vamos tentar gravar em um arquivo temporário. O código a seguir cria um arquivo temporário e grava uma String nele:
@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();
}
Então, como você pode ver - é apenas a criação do arquivo temporário que é interessante e diferente - depois desse ponto, gravar no arquivo é o mesmo.
10. Bloquear arquivo antes de gravar
Finalmente, ao gravar em um arquivo, às vezes você precisa ter certeza de que mais ninguém está gravando nesse arquivo ao mesmo tempo. Basicamente - você precisa bloquear esse arquivo enquanto escreve.
Vamos usarFileChannel para tentar bloquear o arquivo antes de gravá-lo:
@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();
}
Observe que se o arquivo já estiver bloqueado quando tentarmos obter o bloqueio, umOverlappingFileLockException será lançado.
11. Notas
Depois de explorar tantos métodos de gravação em um arquivo, vamos discutir algumas notas importantes:
-
Se tentarmos ler de um arquivo que não existe, umFileNotFoundException será lançado
-
Se tentarmos gravar em um arquivo que não existe, o arquivo será criado primeiro e nenhuma exceção será lançada
-
É muito importante fechar o fluxo depois de usá-lo, pois não está fechado implicitamente, para liberar quaisquer recursos associados a ele
-
No fluxo de saída, o métodoclose() chamaflush() antes de liberar os recursos, o que força todos os bytes armazenados em buffer a serem gravados no fluxo
Olhando para as práticas de uso comuns, podemos ver - por exemplo - quePrintWriter é usado para escrever texto formatado; FileOutputStream para escrever dados binários; DataOutputStream para escrever tipos de dados primitivos; RandomAccessFile para escrever em uma posição específica; FileChannel para escrever mais rápido em arquivos maiores. Algumas das APIs dessas classes permitem mais, mas esse é um bom ponto de partida.
12. Conclusão
Este artigo ilustra as muitas opções de gravação de dados em um arquivo usando Java.
A implementação de todos esses exemplos e trechos de códigocan be found over on GitHub project - este é um projeto baseado em Maven, portanto, deve ser fácil de importar e executar como está.