Enquanto pesquisava no Google, vejo que o uso java.io.File#length()
pode ser lento.
FileChannel
também tem um size()
método disponível.
Existe uma maneira eficiente em java para obter o tamanho do arquivo?
Enquanto pesquisava no Google, vejo que o uso java.io.File#length()
pode ser lento.
FileChannel
também tem um size()
método disponível.
Existe uma maneira eficiente em java para obter o tamanho do arquivo?
Respostas:
Bem, tentei medir com o código abaixo:
Para execuções = 1 e iterações = 1, o método URL é mais rápido na maioria das vezes, seguido pelo canal. Eu corro isso com uma pausa fresca cerca de 10 vezes. Portanto, para acesso único, usar a URL é a maneira mais rápida em que consigo pensar:
Para execuções = 5 e iterações = 50, a imagem é diferente.
O arquivo deve estar armazenando em cache as chamadas para o sistema de arquivos, enquanto os canais e URL possuem alguma sobrecarga.
Código:
fonte
stream.available()
não retorna o tamanho do arquivo. Retorna a quantidade de bytes disponíveis para leitura sem bloquear outros fluxos. Não é necessariamente a mesma quantidade de bytes que o tamanho do arquivo. Para obter o comprimento real de um fluxo, você realmente precisa lê- lo (e contar os bytes de leitura enquanto isso).O benchmark fornecido pelo GHad mede muitas outras coisas (como reflexão, instanciação de objetos etc.), além de obter o comprimento. Se tentarmos nos livrar dessas coisas, em uma ligação recebo os seguintes tempos em microssegundos:
Para 100 execuções e 10000 iterações, recebo:
Eu executei o seguinte código modificado, fornecendo como argumento o nome de um arquivo de 100 MB.
fonte
Todos os casos de teste nesta postagem são falhos, pois acessam o mesmo arquivo para cada método testado. Portanto, o cache do disco é iniciado, no qual os testes 2 e 3 se beneficiam. Para provar meu argumento, peguei o caso de teste fornecido pelo GHAD e alterei a ordem da enumeração e abaixo estão os resultados.
Olhando para o resultado, acho que File.length () é realmente o vencedor.
Ordem de teste é a ordem de saída. Você pode até ver o tempo gasto na minha máquina variando entre as execuções, mas File.Length () quando não é o primeiro e incorrendo no primeiro acesso ao disco.
fonte
Quando modifico seu código para usar um arquivo acessado por um caminho absoluto em vez de um recurso, obtenho um resultado diferente (para 1 execução, 1 iteração e um arquivo de 100.000 bytes - os tempos para um arquivo de 10 bytes são idênticos a 100.000 bytes )
Soma COMPRIMENTO: 33, por Iteração: 33.0
Soma do CHANNEL: 3626, por Iteração: 3626.0
Soma do URL: 294, por Iteração: 294.0
fonte
Em resposta à referência do rgrig, o tempo necessário para abrir / fechar as instâncias FileChannel e RandomAccessFile também precisa ser levado em consideração, pois essas classes abrirão um fluxo para a leitura do arquivo.
Após modificar o benchmark, obtive esses resultados para 1 iterações em um arquivo de 85 MB:
Para 10000 iterações no mesmo arquivo:
Se tudo o que você precisa é do tamanho do arquivo, file.length () é a maneira mais rápida de fazer isso. Se você planeja usar o arquivo para outros fins, como leitura / gravação, o RAF parece ser uma aposta melhor. Só não se esqueça de fechar a conexão do arquivo :-)
fonte
Eu encontrei esse mesmo problema. Eu precisava obter o tamanho do arquivo e a data modificada de 90.000 arquivos em um compartilhamento de rede. Usando Java, e sendo o mais minimalista possível, levaria muito tempo. (Eu precisava obter a URL do arquivo e também o caminho do objeto. Portanto, isso variou um pouco, mas mais de uma hora.) Em seguida, usei um executável nativo do Win32 e fiz a mesma tarefa, apenas descartando o arquivo caminho, modificado e tamanho para o console e o executou em Java. A velocidade foi incrível. O processo nativo e minha manipulação de strings para ler os dados podem processar mais de 1000 itens por segundo.
Portanto, mesmo que as pessoas classifiquem abaixo o comentário acima, essa é uma solução válida e resolveu meu problema. No meu caso, eu conhecia as pastas que precisava dos tamanhos antecipadamente e podia passar isso na linha de comando para o meu aplicativo win32. Passei de horas para processar um diretório para minutos.
O problema também parecia ser específico do Windows. O OS X não teve o mesmo problema e pôde acessar as informações do arquivo de rede tão rápido quanto o SO.
O manuseio de arquivos Java no Windows é terrível. O acesso ao disco local para arquivos é bom. Foram apenas os compartilhamentos de rede que causaram o desempenho terrível. O Windows também pode obter informações sobre o compartilhamento de rede e calcular o tamanho total em menos de um minuto.
--Ben
fonte
Se você deseja o tamanho de vários arquivos em um diretório, use
Files.walkFileTree
. Você pode obter o tamanho doBasicFileAttributes
que receberá.Isso é muito mais rápido do que chamar
.length()
o resultadoFile.listFiles()
ou usarFiles.size()
o resultado deFiles.newDirectoryStream()
. Nos meus casos de teste, era cerca de 100 vezes mais rápido.fonte
Files.walkFileTree
está disponível no Android 26+.Na verdade, acho que os "ls" podem ser mais rápidos. Definitivamente, existem alguns problemas no Java que lidam com a obtenção de informações sobre arquivos. Infelizmente, não existe um método seguro equivalente de ls recursivo para Windows. (o DIR / S de cmd.exe pode ficar confuso e gerar erros em loops infinitos)
No XP, acessando um servidor na LAN, levo 5 segundos no Windows para obter a contagem dos arquivos em uma pasta (33.000) e o tamanho total.
Quando iteramos recursivamente isso em Java, levo mais de 5 minutos. Comecei a medir o tempo necessário para fazer file.length (), file.lastModified () e file.toURI () e o que descobri é que 99% do meu tempo é gasto por essas três chamadas. As 3 chamadas que eu realmente preciso fazer ...
A diferença para 1000 arquivos é 15ms local versus 1800ms no servidor. A verificação do caminho do servidor em Java é ridiculamente lenta. Se o sistema operacional nativo pode ser rápido na verificação dessa mesma pasta, por que o Java não pode?
Como um teste mais completo, usei o WineMerge no XP para comparar a data da modificação e o tamanho dos arquivos no servidor versus os arquivos localmente. Isso estava repetindo a árvore de diretórios inteira de 33.000 arquivos em cada pasta. Tempo total, 7 segundos. java: mais de 5 minutos.
Portanto, a declaração e a pergunta originais do OP são verdadeiras e válidas. É menos perceptível ao lidar com um sistema de arquivos local. Fazer uma comparação local da pasta com 33.000 itens leva 3 segundos no WinMerge e 32 segundos localmente em Java. Então, novamente, java versus nativo é uma desaceleração de 10x nesses testes rudimentares.
Java 1.6.0_22 (mais recente), LAN Gigabit e conexões de rede, o ping é menor que 1ms (ambos no mesmo switch)
Java é lento.
fonte
Do benchmark do GHad, existem algumas questões que as pessoas mencionaram:
1> Como BalusC mencionado: stream.available () é fluido neste caso.
Porque available () retorna uma estimativa do número de bytes que podem ser lidos (ou ignorados) desse fluxo de entrada sem bloquear pela próxima chamada de um método para esse fluxo de entrada.
Então, primeiro a remover a URL desta abordagem.
2> Como StuartH mencionou - a ordem em que o teste é executado também faz a diferença no cache, então faça isso executando o teste separadamente.
Agora inicie o teste:
Quando um canal é executado sozinho:
Quando COMPRIMENTO um é executado sozinho:
Então parece que o COMPRIMENTO é o vencedor aqui:
fonte