Mientras busco en Google, veo que el uso java.io.File#length()
puede ser lento.
FileChannel
tiene un size()
método que también está disponible.
¿Hay alguna manera eficiente en Java para obtener el tamaño del archivo?
Mientras busco en Google, veo que el uso java.io.File#length()
puede ser lento.
FileChannel
tiene un size()
método que también está disponible.
¿Hay alguna manera eficiente en Java para obtener el tamaño del archivo?
Respuestas:
Bueno, intenté medirlo con el siguiente código:
Para carreras = 1 e iteraciones = 1, el método de URL es más rápido la mayoría de las veces seguido de canal. Ejecuto esto con una pausa fresca unas 10 veces. Entonces, para acceder una vez, usar la URL es la forma más rápida en la que puedo pensar:
Para carreras = 5 e iteraciones = 50, la imagen se dibuja de manera diferente.
El archivo debe almacenar en caché las llamadas al sistema de archivos, mientras que los canales y la URL tienen algo de sobrecarga.
Código:
fuente
stream.available()
no devuelve la longitud del archivo. Devuelve la cantidad de bytes que están disponibles para leer sin bloquear otras secuencias. No es necesariamente la misma cantidad de bytes que la longitud del archivo. Para obtener la longitud real de una secuencia, realmente necesita leerla (y contar los bytes leídos mientras tanto).El punto de referencia proporcionado por GHad mide muchas otras cosas (como la reflexión, la creación de instancias de objetos, etc.) además de obtener la longitud. Si intentamos deshacernos de estas cosas, en una llamada obtengo los siguientes tiempos en microsegundos:
Por 100 ejecuciones y 10000 iteraciones obtengo:
Ejecuté el siguiente código modificado dando como argumento el nombre de un archivo de 100MB.
fuente
Todos los casos de prueba en esta publicación son defectuosos ya que acceden al mismo archivo para cada método probado. Entonces, las patadas de almacenamiento en caché de disco en las que se benefician las pruebas 2 y 3. Para probar mi punto, tomé el caso de prueba proporcionado por GHAD y cambié el orden de enumeración y a continuación se muestran los resultados.
Mirando el resultado, creo que File.length () es realmente el ganador.
El orden de prueba es el orden de salida. Incluso puede ver que el tiempo empleado en mi máquina varió entre ejecuciones, pero File.Length () cuando no fue el primero, e incurrió en el primer acceso al disco ganado.
fuente
Cuando modifico su código para usar un archivo al que se accede por una ruta absoluta en lugar de un recurso, obtengo un resultado diferente (para 1 ejecución, 1 iteración y un archivo de 100,000 bytes; los tiempos para un archivo de 10 bytes son idénticos a 100,000 bytes )
LONGITUD suma: 33, por iteración: 33.0
CANAL suma: 3626, por iteración: 3626.0
Suma de URL: 294, por iteración: 294.0
fuente
En respuesta al punto de referencia de rgrig, el tiempo necesario para abrir / cerrar las instancias FileChannel y RandomAccessFile también debe tenerse en cuenta, ya que estas clases abrirán una secuencia para leer el archivo.
Después de modificar el punto de referencia, obtuve estos resultados para 1 iteraciones en un archivo de 85 MB:
Para 10000 iteraciones en el mismo archivo:
Si todo lo que necesita es el tamaño del archivo, file.length () es la forma más rápida de hacerlo. Si planea utilizar el archivo para otros fines, como leer / escribir, RAF parece ser una mejor opción. Simplemente no olvide cerrar la conexión de archivo :-)
fuente
Me encontré con este mismo problema. Necesitaba obtener el tamaño del archivo y la fecha de modificación de 90,000 archivos en un recurso compartido de red. Usando Java, y siendo lo más minimalista posible, tomaría mucho tiempo. (Necesitaba obtener la URL del archivo y la ruta del objeto también. Por lo tanto, varió un poco, pero más de una hora). Luego utilicé un ejecutable Win32 nativo, e hice la misma tarea, simplemente volqué el archivo ruta, modificado y tamaño a la consola, y ejecutó eso desde Java. La velocidad fue asombrosa. El proceso nativo y el manejo de mi cadena para leer los datos podrían procesar más de 1000 elementos por segundo.
Entonces, aunque las personas clasificaron el comentario anterior, esta es una solución válida y resolvió mi problema. En mi caso, sabía de antemano las carpetas que necesitaba los tamaños, y podría pasar eso en la línea de comandos a mi aplicación win32. Pasé de horas para procesar un directorio a minutos.
El problema también parecía ser específico de Windows. OS X no tenía el mismo problema y podía acceder a la información de los archivos de red tan rápido como el SO podía hacerlo.
El manejo de archivos Java en Windows es terrible. Sin embargo, el acceso al disco local para los archivos está bien. Fueron solo los recursos compartidos de red los que causaron el terrible rendimiento. Windows también podría obtener información sobre el recurso compartido de red y calcular el tamaño total en menos de un minuto.
--Ben
fuente
Si desea el tamaño de archivo de varios archivos en un directorio, use
Files.walkFileTree
. Puede obtener el tamaño delBasicFileAttributes
que recibirá.Esto es mucho más rápido que invocar
.length()
el resultado deFile.listFiles()
o usarFiles.size()
el resultado deFiles.newDirectoryStream()
. En mis casos de prueba fue aproximadamente 100 veces más rápido.fuente
Files.walkFileTree
está disponible en Android 26+.En realidad, creo que el "ls" puede ser más rápido. Definitivamente, hay algunos problemas en Java relacionados con la obtención de información de archivo. Lamentablemente, no existe un método seguro equivalente de ls recursivo para Windows. (DIR / S de cmd.exe puede confundirse y generar errores en bucles infinitos)
En XP, al acceder a un servidor en la LAN, me toma 5 segundos en Windows obtener el recuento de los archivos en una carpeta (33,000) y el tamaño total.
Cuando itero recursivamente a través de esto en Java, me lleva más de 5 minutos. Comencé a medir el tiempo que toma hacer file.length (), file.lastModified () y file.toURI () y lo que descubrí es que esas 3 llamadas me toman el 99% de mi tiempo. Las 3 llamadas que realmente necesito hacer ...
La diferencia para 1000 archivos es de 15 ms local frente a 1800 ms en el servidor. El escaneo de la ruta del servidor en Java es ridículamente lento. Si el sistema operativo nativo puede ser rápido al escanear esa misma carpeta, ¿por qué no puede Java?
Como una prueba más completa, utilicé WineMerge en XP para comparar la fecha de modificación y el tamaño de los archivos en el servidor versus los archivos localmente. Esto iteraba sobre el árbol de directorios completo de 33,000 archivos en cada carpeta. Tiempo total, 7 segundos. Java: más de 5 minutos.
Por lo tanto, la declaración original y la pregunta del OP son verdaderas y válidas. Es menos notable cuando se trata de un sistema de archivos local. Hacer una comparación local de la carpeta con 33,000 elementos lleva 3 segundos en WinMerge y 32 segundos localmente en Java. De nuevo, java versus native es una desaceleración 10x en estas pruebas rudimentarias.
Java 1.6.0_22 (más reciente), LAN Gigabit y conexiones de red, el ping es inferior a 1 ms (ambos en el mismo conmutador)
Java es lento
fuente
Desde el punto de referencia de GHad, hay algunos problemas que la gente ha mencionado:
1> Como BalusC mencionó: stream.available () fluye en este caso.
Porque disponible () devuelve una estimación del número de bytes que se pueden leer (u omitir) de esta secuencia de entrada sin bloquear mediante la próxima invocación de un método para esta secuencia de entrada.
Así que primero para eliminar la URL de este enfoque.
2> Como mencionó StuartH: el orden en que se ejecuta la prueba también hace la diferencia de caché, así que sáquelo ejecutando la prueba por separado.
Ahora comience la prueba:
Cuando el CANAL uno corre solo:
Cuando LONGITUD se corre solo:
Parece que LENGTH one es el ganador aquí:
fuente