fileIn = new FileInputStream(originalFile);
fileOut = new FileOutputStream(toFile);
int ch;
while ((ch = pmFileIn.read()) != -1){
fileOut.write(ch);
}
fileIn.close();
fileOut.close();
Nio: como copiar arquivos?
17 Respostas
Olá
-
Estude melhor a documentação do java.io. Há meios mais rápidos de que copiar arquivos caracter por caracter. Aliás não use chars para copiar arquivos.
-
Com java.nio se pode melhorar o desempenho desde que use buffers e todas as boas práticas.
-
No ConexãoJava haverá uma palestra sobre java.nio e aqui no GUJ há um artigo sobre java.nio com um exemplo exatamente igual ao que quer fazer.
[]s
Luca
Acredite se quiser, mas copiar 1 arquivo com java.nio é mais facil que com java.io!
FileChannel from = new RandomAccessFile("from.txt", "r").getChannel();
FileChannel to= new RandomAccessFile("to.txt", "w").getChannel();
from.transferTo(0, from.size(), to);
Aqui tem ótimos exemplos acho que você vai gostar
http://www.javaalmanac.com/egs/java.nio/File2File.html
while ((ch = pmFileIn.read()) != -1){
fileOut.write(ch);
}
while (((ch = pmFileIn.read()) != -1) && !stop){
fileOut.write(ch);
}
try {
// Create channel on the source
FileChannel srcChannel = new FileInputStream("srcFilename").getChannel();
// Create channel on the destination
FileChannel dstChannel = new FileOutputStream("dstFilename").getChannel();
// Copy file contents from source to destination
dstChannel.transferFrom(srcChannel, 0, srcChannel.size());
// Close the channels
srcChannel.close();
dstChannel.close();
} catch (IOException e) {
}
Ler a documentação ajuda viu! :x
A responsta ta na descrição do método!
Thread t = Thread.currentThread();
...
try {
from.transferTo(0, to.size(), to);
} catch(ClosedByInterruptException e) {
//thread for interrompida! paramos aqui
}
...
em outra thread simplesmente fazemos:
t.interrupt();
Ou ainda podemos simplesmente fechar um dos channels.
Vale lembrar que transfer[To/From] quando interrompidos não tem como saber quantos bytes foram transferidos com sucesso.
Ler a documentação ajuda viu! :x
A responsta ta na descrição do método!…
Ou ainda podemos simplesmente fechar um dos channels.
Vale lembrar que transfer[To/From] quando interrompidos não tem como saber quantos bytes foram transferidos com sucesso.
:scrambleup: louds, my friend, eu li a documentação…
:agrue:
O lance é que com o interrupt() eu não tenho certeza de como, quando ou se o serviço vai parar… Tentei também fechar um dos canais, mas aparentemente não funcionou… Se eu mando fechar um canal, parece, sei lá, que ele tá bloqueado e a chamada close() parece esperar até o final da cópia pra ocorrer (mesmo numa Thread separada…)
Mas, realmente, minha primeira idéia era o interrupt(), como você pode ver em http://www.guj.com.br/forum/viewtopic.php?t=14331… Mas não rolou… Tem alguma dica, velho?
Ps.: a documentação de Java é muito boa e tal, mas nem sempre a Sun tem as respostas pra todas as nossas perguntas… 
Se você está usando Windows, FileChannel.transferFrom ou .transferTo são implementados via mapeamento de arquivos em memória.
(Se você adora ler fontes em C, e tem paciência suficiente para baixar o fonte COMPLETO do JDK 1.4, baixe a versão SCSL do código-fonte do JDK, e veja os arquivos j2sesrcwindows
ativejavasun
iochFileChannelImpl.c e srcshareclassessun
iochFileChannelImpl.java).
A transferência é feita de modo tal que não pode ser interrompida, porque é como se fosse um “System.arraycopy”. Você consegue interromper um “System.arraycopy”?
Se você quer copiar as coisas rápido (e põe rápido nisso; é mais rápido que em C++, a menos que você use APIs do Windows), use transferFrom ou transferTo.
Se você quer controle, use o velho e bom FileInputStream/FileOutputStream e aposte uma corrida com o Rubinho Barrichello…
:scrambleup: Caramba! Não sabia disso… E ainda fiquei com raiva do meu código… :lol: Bom, agora que sei disso, vou procurar, sei lá, impedir apenas que a cópia do próximo arquivo comece quando o usuário cancelar uma operação dessas… Mas, é verdade, a diferença entre os tipos de cópia (FileChannel New I/O e FileStreams I/O convencional) é monstruosa… Estou usando um computador com um processador de 2.4GHz e a cópia com “old” I/O chegou a um pico de 71% de uso do processador, enquanto a outra (New I/O), além de rápida, exigiu menos da máquina. Mas tudo tem seu preço… Desempenho custa controle. Pessoalmente, fico com desempenho…
:arrow: :?: Curiosidade… Em outros sistemas que não o Window$, a cópia via FileChannel também é impossível de ser parada?
:arrow: :!: Tenho uma outra dúvida sobre FileChannel que é sobre monitorar progresso com ele… Desculpem por estar fazendo isso, mas, preciso muito de uma :idea: e até agora não tive nenhuma resposta em 2 dias… Essa dúvida de monitorar progresso está em http://www.guj.com.br/forum/viewtopic.php?t=14391. Novamente, desculpem linkar esse tópico a outro desta forma, mas existe um fator desespero…
martui, desculpe por ter sido meio grosso.
Porem nunca precisei explicitamente interromper 1 copia via transferXXX.
Uma solução que eu vejo é voce implementar copia usando buffers/nio de forma análoga a feita com streams.
thingol, eu imaginei que em win32 eles usassem a API de filecopy, mas vai lá saber qual a performance dela…
:scrambleup: Cara, não esquente a cabeça não… Nem pensei nisso…
Como seria isso? Será que você poderia me indicar um exemplo? E… Mais uma coisa: quanto a performance… Usar buffers/nio seria tão eficiente quanto usar FileChannel? Qual seria uma comparação (em termos de tempo) entre usar Streams “old” I/O, FileChannel e buffers/nio?
Em Linux:
transferTo chama a API sendfile. Como quase todas as APIs do Unix podem ser interrompidas (errno = EINTR), acho que dá para interromper sem problemas, mas isso é o caso de testar.
Em Solaris:
transferTo chama a API sendfilev, carregada dinamicamente de /usr/lib/libsendfile.so.1. Fora isso, é igual ao Linux.
Estou falando baseado apenas no código fonte da 1.4.2 do JDK da Sun, fonte j2se/src/solaris/native/sun/nio/ch/FileChannelImpl.c, função Java_sun_nio_ch_FileChannelImpl_transferTo0().
Não sei se o JDK da IBM, ou da BEA, implementam FileChannel.transferTo dessa maneira.
Droga, apertei o botão errado … o botão de criar nova mensagem deveria ser mais escondido que o botão de reply.
É mais fácil fazer o benchmark do que falar, mas estou chutando que teríamos a seguinte situação:
Tempo gasto:
FileChannel.transferTo < NIO Buffers < BufferedXStream+FileXStream < FileXStream puro
Consumo de memória:
FileChannel.transferTo < FileXStream < BufferedXStream + FileXStream < NIO Bufffers
Consumo de CPU (supondo que, se você tiver um disco ATA, que esteja configurado para usar DMA para reduzir o consumo de CPU em I/O):
FileChannel.transferTo < NIO Buffers < BufferedXStream + FileXStream < FileXStream
É estranho que eu esteja chutando que BufferedXStream + FileXStream consuma menos CPU que FileXStream sozinho (afinal, está executando mais código), mas é que BufferedXStream evita que FileXStream esteja constantemente acessando o sistema operacional via JNI, o que consome um monte de CPU.
Obviamente é necessário fazer o teste, porque na prática aparecem coisas que não são esperadas só pela teoria. (Para explicar os resultados, é preciso mudar a teoria…)
:scrambleup: Entendo… Se não for pedir demais… Digamos que o FileChannel fosse assim, uma Ferrari e os clássicos FileXXputStream fossem as Minardis… Os Buffers/nio seriam o que?
E mais uma coisa:
Como eu faço isso? Nunca fiz e nem vi exemplos ainda… Onde tem exemplos sobre isso? Alguém poderia fornecê-los?
Isso copia usando um buffer.
ByteBuffer bb = ByteBuffer.allocateDirect(2048);
FileChannel from = ...
FileChannel to = ...
bb.clear();
while(from.read(bb) != -1) {
bb.flip();
to.write(bb);
bb.clear();
}
:scrambleup: Eu tentei esse seu código e ganhei de presente uma java.io.IOException: Acesso negado
at sun.nio.ch.FileChannelImpl.truncate0(Native Method)
at sun.nio.ch.FileChannelImpl.map(Unknown Source)
at sun.nio.ch.FileChannelImpl.transferFromFileChannel(Unknown Source)
at sun.nio.ch.FileChannelImpl.transferFrom(Unknown Source)
at br.inf.empresaqualquer.update.util.FileHandler.copyFile(FileHandler.java:70) Alguma idéia do que faltou eu fazer?
:arrow: Estou usando Window$.
:scrambleup: Deculpa, pessoal, resolvi o problema… Bastava comentar uma linha que tinha ficado de um código antigo que estava ali… Foi mal… :roll:
Até agora, o esquema com o ByteBuffer foi bem rapidinho, quase se equiparando ao FileChannel puro. Não dá pra saber quem é mais rápido…
Olá!
Como estás a fazer cópia de arquivos, poderás aumentar o tamanho do buffer um pouco, que deve melhorar o desempenho.
Se quiser, faça testes com 8192 bytes ou 16384 bytes de buffer.