Estou escrevendo um pedaço de código:
OutputStream outputStream = new FileOutputStream(createdFile);
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(gzipOutputStream));
Preciso fechar todos os fluxos ou gravadores como o seguinte?
gzipOutputStream.close();
bw.close();
outputStream.close();
Ou será bom apenas fechar o último fluxo?
bw.close();
java
file-io
outputstream
writer
Adon Smith
fonte
fonte
BufferedWriter
, pode ser necessário gravar dados em buffer no fluxo subjacente, que no seu exemplo já está fechado. Evitar esses problemas é outra vantagem das abordagens de tentativa com recursos mostradas nas respostas.Respostas:
Supondo que todos os fluxos são criados bem, sim, apenas o encerramento
bw
é muito bem com essas implementações de fluxo ; mas isso é uma grande suposição.Eu usaria o try-with-resources ( tutorial ) para que quaisquer problemas na construção dos fluxos subseqüentes que geram exceções não deixem os fluxos anteriores suspensos e, assim, você não precise confiar na implementação do fluxo para encerrar a chamada. o fluxo subjacente:
Observe que você não liga mais
close
.Nota importante : Para que a tentativa com recursos os feche, você deve atribuir os fluxos às variáveis ao abri-las, não é possível usar o aninhamento. Se você usar o aninhamento, uma exceção durante a construção de um dos fluxos posteriores (por exemplo,
GZIPOutputStream
) deixará aberto qualquer fluxo construído pelas chamadas aninhadas dentro dele. Do JLS §14.20.3 :Observe a palavra "variáveis" (ênfase minha) .
Por exemplo, não faça isso:
... porque uma exceção do
GZIPOutputStream(OutputStream)
construtor (que diz que pode ser lançadaIOException
e grava um cabeçalho no fluxo subjacente) deixariaFileOutputStream
aberta. Como alguns recursos têm construtores que podem ser lançados e outros não, é um bom hábito apenas listá-los separadamente.Podemos verificar novamente nossa interpretação dessa seção JLS com este programa:
... que tem a saída:
Observe que não há chamadas para
close
lá.Se corrigirmos
main
:então recebemos as
close
chamadas apropriadas :(Sim, duas chamadas para
InnerMost#close
estão corretas; uma é deMiddle
e a outra de tentativa com recursos.)fonte
java.io
. Alguns fluxos - generalizando, alguns recursos - são lançados pelos construtores. Portanto, garantir que vários recursos sejam abertos individualmente para que possam ser fechados com segurança se um recurso subsequente for lançado é apenas um bom hábito, na minha opinião. Você pode optar por não fazer isso se não concordar, tudo bem.GZIPOutputStream
o construtor escreve um cabeçalho no fluxo. E assim pode jogar. Então agora a posição é se eu acho que vale a pena se preocupar em tentar fechar o fluxo depois de escrever jogado. Sim: eu abri, eu deveria pelo menos tentar fechá-lo.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.
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?
Vamos começar com FileOutputStream, que chama
open
para fazer todo o trabalho real.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
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
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.
fonte
GZIPOutputStream(OutputStream)
documentosIOException
e, olhando a fonte, na verdade escreve um cabeçalho. Portanto, não é teórico que o construtor possa lançar. Você pode achar que não há problema em deixar o subjacente emFileOutputStream
aberto depois de escrever para ele. Eu não.Se todos os fluxos tiverem sido instanciados, o fechamento apenas do lado externo será bom.
A documentação na
Closeable
interface afirma que método fechado:Os recursos do sistema de liberação incluem fluxos de fechamento.
Também afirma que:
Portanto, se você fechá-los explicitamente depois, nada de errado acontecerá.
fonte
Eu prefiro usar
try(...)
sintaxe (Java 7), por exemplofonte
Tudo bem se você fechar apenas o último fluxo - a chamada final também será enviada para os fluxos subjacentes.
fonte
Não, o nível mais alto
Stream
oureader
garantirá que todos os fluxos / leitores subjacentes sejam fechados.Verifique a implementação do
close()
método do seu fluxo de nível superior.fonte
No Java 7, há um recurso try-with-resources . Você não precisa fechar explicitamente seus fluxos, ele cuidará disso.
fonte