Você pode fechar o fluxo mais externo, na verdade, não precisa reter todos os fluxos agrupados e pode usar o Java 7 try-with-resources.
try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
new GZIPOutputStream(new FileOutputStream(createdFile)))) {
// write to the buffered writer
}
Se você se inscrever no YAGNI, ou não precisar, deve adicionar apenas o código que realmente precisa. Você não deve adicionar o código que imagina ser necessário, mas na realidade não faz nada de útil.
Pegue este exemplo e imagine o que poderia dar errado se você não fizesse isso e qual seria o impacto?
try (
OutputStream outputStream = new FileOutputStream(createdFile);
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream);
OutputStreamWriter osw = new OutputStreamWriter(gzipOutputStream);
BufferedWriter bw = new BufferedWriter(osw)
) {
// ...
}
Vamos começar com FileOutputStream, que chama open
para fazer todo o trabalho real.
/**
* Opens a file, with the specified name, for overwriting or appending.
* @param name name of file to be opened
* @param append whether the file is to be opened in append mode
*/
private native void open(String name, boolean append)
throws FileNotFoundException;
Se o arquivo não for encontrado, não há recurso subjacente para fechar, portanto, fechá-lo não fará nenhuma diferença. Se o arquivo existir, ele deve lançar uma FileNotFoundException. Portanto, não há nada a ganhar tentando fechar o recurso somente dessa linha.
O motivo pelo qual você precisa fechar o arquivo é quando o arquivo é aberto com êxito, mas você mais tarde recebe um erro.
Vamos ver o próximo stream GZIPOutputStream
Há código que pode gerar uma exceção
private void writeHeader() throws IOException {
out.write(new byte[] {
(byte) GZIP_MAGIC, // Magic number (short)
(byte)(GZIP_MAGIC >> 8), // Magic number (short)
Deflater.DEFLATED, // Compression method (CM)
0, // Flags (FLG)
0, // Modification time MTIME (int)
0, // Modification time MTIME (int)
0, // Modification time MTIME (int)
0, // Modification time MTIME (int)
0, // Extra flags (XFLG)
0 // Operating system (OS)
});
}
Isso grava o cabeçalho do arquivo. Agora, seria muito incomum você poder abrir um arquivo para gravação, mas não conseguir escrever nem 8 bytes, mas vamos imaginar que isso poderia acontecer e não fecharemos o arquivo posteriormente. O que acontece com um arquivo se ele não estiver fechado?
Você não recebe gravações não liberadas, elas são descartadas e, nesse caso, não há bytes gravados com sucesso no fluxo que não sejam armazenados em buffer neste momento. Mas um arquivo que não está fechado não fica para sempre, mas o FileOutputStream tem
protected void finalize() throws IOException {
if (fd != null) {
if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
flush();
} else {
/* if fd is shared, the references in FileDescriptor
* will ensure that finalizer is only called when
* safe to do so. All references using the fd have
* become unreachable. We can call close()
*/
close();
}
}
}
Se você não fechar um arquivo, ele será fechado de qualquer maneira, mas não imediatamente (e, como eu disse, os dados deixados em um buffer serão perdidos dessa maneira, mas não há nenhum neste momento)
Qual é a consequência de não fechar o arquivo imediatamente? Em condições normais, você potencialmente perde alguns dados e os descritores de arquivos ficam em potencial. Mas se você possui um sistema em que pode criar arquivos, mas não pode gravar nada neles, há um problema maior. ou seja, é difícil imaginar por que você está tentando criar esse arquivo repetidamente, apesar de estar falhando.
OutputStreamWriter e BufferedWriter não lançam IOException em seus construtores, portanto, não está claro qual problema eles causariam. No caso do BufferedWriter, você pode obter um OutOfMemoryError. Nesse caso, ele acionará imediatamente um GC, que, como vimos, fechará o arquivo de qualquer maneira.