Pergunta

Eu só jogou com sistema de arquivos Java API, e desceu com a função a seguir, usado para copiar arquivos binários. A fonte original veio a partir da Web, mas eu adicionei try / catch / finally cláusulas para ter certeza de que, se algo de errado acontecer, os fluxos de buffer seria fechado (e, portanto, meus ressources OS libertou) antes de quiting a função.

Eu aparadas para baixo a função para mostrar o padrão:

public static void copyFile(FileOutputStream oDStream, FileInputStream oSStream) throw etc...
{
   BufferedInputStream oSBuffer = new BufferedInputStream(oSStream, 4096);
   BufferedOutputStream oDBuffer = new BufferedOutputStream(oDStream, 4096);

   try
   { 
      try
      { 
         int c;

         while((c = oSBuffer.read()) != -1)  // could throw a IOException
         {
            oDBuffer.write(c);  // could throw a IOException
         }
      }
      finally
      {
         oDBuffer.close(); // could throw a IOException
      }
   }
   finally
   {
      oSBuffer.close(); // could throw a IOException
   }
}

Tanto quanto eu entendo, eu não posso colocar os dois close() na cláusula finally, porque a primeira close() poderia muito bem jogar, e em seguida, o segundo não seria executado.

Eu sei C # tem o Eliminar padrão que teria lidado com isso com a palavra-chave using.

Eu mesmo conheço melhor a C ++ código teria sido algo como (usando um Java-like API):

void copyFile(FileOutputStream & oDStream, FileInputStream & oSStream)
{
   BufferedInputStream oSBuffer(oSStream, 4096);
   BufferedOutputStream oDBuffer(oDStream, 4096);

   int c;

   while((c = oSBuffer.read()) != -1)  // could throw a IOException
   {
      oDBuffer.write(c);  // could throw a IOException
   }

   // I don't care about resources, as RAII handle them for me
}

Eu estou faltando alguma coisa, ou eu realmente tem que produzir código feio e inchado em Java apenas para exceções identificador no método close() de um Buffered Stream?

(Por favor, me diga que estou em algum lugar errado ...)

EDIT: É mim, ou quando atualizando esta página, eu vi tanto a questão e todas as respostas diminuiu em um ponto em um par de minutos? Alguém está se divertindo muito enquanto remaning anônimo?

EDIT 2: McDowell ofereceu uma ligação muito interessante que eu senti que tinha que mencionar aqui: http: //illegalargumentexception.blogspot .com / 2008/10 / java-to-how-não-faz-de-mess-de-stream.html

EDIT 3: Após a ligação do McDowell, eu caiu sobre uma proposta de Java 7 de um padrão semelhante ao C # usando padrão: http://tech.puredanger.com/java7/#resourceblock . Meu problema é descrito explicitamente. Aparentemente, mesmo com a do Java 7, os problemas continuam.

Foi útil?

Solução

O try / finally padrão é a maneira correta de lidar com fluxos na maioria dos casos para Java 6 e inferiores.

Alguns estão defendendo fluxos fechando silenciosamente. Tenha cuidado para fazer isso por estas razões: Java: como não fazer uma confusão de fluxo de manipulação


Java 7 introduz try-with-recursos :

/** transcodes text file from one encoding to another */
public static void transcode(File source, Charset srcEncoding,
                             File target, Charset tgtEncoding)
                                                             throws IOException {
    try (InputStream in = new FileInputStream(source);
         Reader reader = new InputStreamReader(in, srcEncoding);
         OutputStream out = new FileOutputStream(target);
         Writer writer = new OutputStreamWriter(out, tgtEncoding)) {
        char[] buffer = new char[1024];
        int r;
        while ((r = reader.read(buffer)) != -1) {
            writer.write(buffer, 0, r);
        }
    }
}

AutoCloseable tipos será fechada automaticamente :

public class Foo {
  public static void main(String[] args) {
    class CloseTest implements AutoCloseable {
      public void close() {
        System.out.println("Close");
      }
    }
    try (CloseTest closeable = new CloseTest()) {}
  }
}

Outras dicas

Existem problemas, mas o código encontrado deitado sobre a web é realmente pobre.

Fechando as correntes de tampão fecha a baixo fluxo. Você realmente não quero fazer isso. Tudo o que você quer fazer é nivelado o fluxo de saída. Também não há nenhum ponto em especificar as correntes subjacentes são para arquivos. Desempenho é uma porcaria porque você está copiando um byte de cada vez (na verdade, se você usar uso java.io pode usar transferTo / transferFrom que é um pouco mais rápido ainda). Enquanto estamos nisso, os nomes das variáveis ??de mamar aos. Assim:

public static void copy(
    InputStream in, OutputStream out
) throw IOException {
    byte[] buff = new byte[8192];
    for (;;) {
        int len = in.read(buff);
        if (len == -1) {
            break;
        }
        out.write(buff, 0, len);
    }
}

Se você está usando try-finally muito, então você pode levar para fora com o "executar em torno de" idioma.

Na minha opinião: Java deve ter alguma forma de fechar os recursos no final do escopo. Eu sugiro adicionar private como um operador de sufixo unária para fechar no final do bloco de inclusão.

Sim, isso é como funciona o Java. Há controle de inversão - o usuário do objeto tem que saber como limpar o objeto, em vez do próprio objeto limpeza após si. Esta, infelizmente, leva a um monte de código de limpeza espalhados por todo o seu código Java.

C # tem a "utilizar" palavra-chave para chamar automaticamente Descarte quando um objeto sai do escopo. Java não tem tal coisa.

Infelizmente, este tipo de código tende a ficar um pouco inchado em Java.

A propósito, se uma das chamadas para oSBuffer.read ou oDBuffer.write lança uma exceção, então você provavelmente vai querer deixar isso permeado exceção até a hierarquia chamada.

Tendo uma chamada subterrâneo a fim () dentro de uma cláusula finalmente irá causar a excepção original para ser substituída por uma produzido pela estreita () - chamada. Em outras palavras, a falha close () - método pode esconder a exceção original produzida pelo read () ou write (). Então, eu acho que você deseja ignorar as exceções lançadas por perto () se e somente se os outros métodos não jogar.

Normalmente, eu resolver isso, incluindo um close-chamada explícita, dentro da tentativa interna:

  try {
    while (...) {
      read...
      write...
    }
    oSBuffer.close(); // exception NOT ignored here
    oDBuffer.close(); // exception NOT ignored here
  } finally {
    silentClose(oSBuffer); // exception ignored here
    silentClose(oDBuffer); // exception ignored here
  }
  static void silentClose(Closeable c)  {
    try {
      c.close();
    } catch (IOException ie) {
      // Ignored; caller must have this intention
    }
  }

Finalmente, para o desempenho, o código deve provavelmente trabalhar com buffers (vários bytes por leitura / gravação). Não pode voltar que por números, mas menos chamadas devem ser mais eficiente do que a adição de fluxos de buffer no topo.

Para tarefas IO comuns, como copiar um arquivo, código como o mostrado acima é reinventar a roda. Infelizmente, o JDK não fornece quaisquer utilitários de nível superior, mas apache commons-io faz.

Por exemplo, FileUtils contém vários métodos de utilidade para trabalhar com arquivos e diretórios (incluindo fotocópias). Por outro lado, se você realmente precisa usar o apoio IO no JDK, IOUtils contém um conjunto de closeQuietly () métodos que os leitores fim, Gravadores, fluxos, etc. sem lançar excepções.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top