Estoy tratando de encontrar la mejor manera de encontrar la cantidad de archivos en un directorio en particular cuando hay una gran cantidad de archivos (> 100,000).
Cuando hay tantos archivos, la ejecución ls | wc -l
tarda bastante tiempo en ejecutarse. Creo que esto se debe a que está devolviendo los nombres de todos los archivos. Estoy tratando de ocupar la menor cantidad de IO de disco posible.
He experimentado con algunos scripts de shell y Perl en vano. ¿Algunas ideas?
Respuestas:
Por defecto
ls
ordena los nombres, lo que puede llevar un tiempo si hay muchos. Además, no habrá salida hasta que se lean y se ordenen todos los nombres. Use lals -f
opción para desactivar la clasificación.Tenga en cuenta que esto también permitirá
-a
, por lo que.
,..
y otros archivos que comienzan con.
será contado.fuente
ls
.stat()
llamada que sels
hace en cada archivo.find
no funcionastat()
así más rápido.ls -f
No hacestat()
tampoco. Pero, por supuesto, ambosls
yfind
llamarstat()
cuando se utilizan ciertas opciones, comols -l
ofind -mtime
.ls -fR | wc -l
La forma más rápida es un programa especialmente diseñado, como este:
De mis pruebas sin tener en cuenta el caché, ejecuté cada una de estas aproximadamente 50 veces cada una contra el mismo directorio, una y otra vez, para evitar el sesgo de datos basado en caché, y obtuve aproximadamente los siguientes números de rendimiento (en tiempo de reloj real):
Ese último
dircnt
, es el programa compilado de la fuente anterior.EDITAR 2016-09-26
Debido a la demanda popular, he reescrito este programa para que sea recursivo, por lo que caerá en subdirectorios y continuará contando archivos y directorios por separado.
Como está claro que algunas personas quieren saber cómo hacer todo esto, tengo muchos comentarios en el código para tratar de hacer obvio lo que está sucediendo. Escribí esto y lo probé en Linux de 64 bits, pero debería funcionar en cualquier sistema compatible con POSIX, incluido Microsoft Windows. Los informes de errores son bienvenidos; Me complace actualizar esto si no puede hacerlo funcionar en su AIX o OS / 400 o lo que sea.
Como puede ver, es mucho más complicado que el original y necesariamente así: debe existir al menos una función para que se invoque de forma recursiva a menos que desee que el código se vuelva muy complejo (por ejemplo, administrar una pila de subdirectorios y procesarla en un solo bucle). Como tenemos que verificar los tipos de archivos, entran en juego las diferencias entre diferentes sistemas operativos, bibliotecas estándar, etc., por lo que he escrito un programa que intenta ser utilizable en cualquier sistema donde se compilará.
Hay muy poca comprobación de errores, y la
count
función en sí misma no informa errores. Las únicas llamadas que realmente pueden fallar sonopendir
ystat
(si no tienes suerte y tienes un sistema que yadirent
contiene el tipo de archivo). No estoy paranoico acerca de verificar la longitud total de los nombres de ruta de subdirección, pero en teoría, el sistema no debería permitir ningún nombre de ruta que sea más largo quePATH_MAX
. Si hay dudas, puedo solucionarlo, pero es solo más código que debe explicarse a alguien que está aprendiendo a escribir C. Este programa pretende ser un ejemplo de cómo sumergirse en subdirectorios de forma recursiva.EDITAR 2017-01-17
He incorporado dos cambios sugeridos por @FlyingCodeMonkey:
lstat
lugar destat
. Esto cambiará el comportamiento del programa si tiene directorios enlazados en el directorio que está escaneando. El comportamiento anterior era que el subdirectorio (vinculado) tendría su recuento de archivos agregado al recuento general; El nuevo comportamiento es que el directorio vinculado contará como un solo archivo y no se contará su contenido.EDITAR 2017-06-29
Con suerte, esta será la última edición de esta respuesta :)
He copiado este código en un repositorio de GitHub para que sea un poco más fácil obtener el código (en lugar de copiar / pegar, solo puede descargar la fuente ), además hace que sea más fácil para cualquier persona sugerir una modificación enviando un pull -solicitud de GitHub.
La fuente está disponible bajo la licencia Apache 2.0. Parches * bienvenido!
fuente
gcc -o dircnt dircnt.c
y el uso es como esto./dircnt some_dir
¿Intentaste encontrar? Por ejemplo:
fuente
find /usr/share | wc -l
(~ 137,000 archivos) es aproximadamente un 25% más rápido quels -R /usr/share | wc -l
(~ 160,000 líneas incluyendo nombres de directorios, totales de directorios y líneas en blanco) en la primera ejecución de cada uno y al menos dos veces más rápido al comparar ejecuciones posteriores (en caché).find
es más rápida quels
por la forma en que la está utilizandols
. Si deja de ordenarls
yfind
tiene un rendimiento similar.find, ls y perl probados contra 40 000 archivos: misma velocidad (aunque no intenté borrar el caché):
y con perl opendir / readdir, al mismo tiempo:
nota: utilicé / bin / ls -f para asegurarme de omitir la opción de alias que podría ralentizarse un poco y -f para evitar el orden de los archivos. ls sin -f es dos veces más lento que find / perl, excepto si ls se usa con -f, parece ser la misma hora:
También me gustaría tener algún script para preguntar directamente al sistema de archivos sin toda la información innecesaria.
pruebas basadas en la respuesta de Peter van der Heijden, glenn jackman y mark4o.
Thomas
fuente
ls -l | wc -l
una carpeta en un HDD externo de 2.5 "con archivos de 1M, la operación tarda unos 3 minutos en finalizar. La segunda vez toma 12 segundos IIRC. También esto podría depender de su sistema de archivos. I estaba usandoBtrfs
.$ time perl -e 'opendir D, "."; @files = readdir D; closedir D; print scalar(@files)."\n"' 1315029 real 0m0.580s user 0m0.302s sys 0m0.275s
Puede cambiar la salida en función de sus requisitos, pero aquí hay un bash one-liner que escribí para contar recursivamente e informar el número de archivos en una serie de directorios con nombres numéricos.
Esto busca de forma recursiva todos los archivos (no directorios) en el directorio dado y devuelve los resultados en un formato similar al hash. Los ajustes simples al comando de búsqueda podrían hacer que el tipo de archivos que busca contar sea más específico, etc.
Resultados en algo como esto:
fuente
ls -1 ${dir}
no funcionará correctamente sin más espacios. Además, no hay garantía de quels
se pueda pasar el nombre devuelto porfind
, ya quels
escapa a los caracteres no imprimibles para consumo humano. (mkdir $'oddly\nnamed\ndirectory'
si quieres un caso de prueba particularmente interesante). Vea por qué no debe analizar la salida de ls (1)Sorprendentemente para mí, un hallazgo básico es muy comparable a ls -f
versus
Por supuesto, los valores en el tercer lugar decimal cambian un poco cada vez que ejecuta cualquiera de estos, por lo que son básicamente idénticos. Sin embargo
find
, tenga en cuenta que devuelve una unidad adicional, ya que cuenta el directorio real en sí (y, como se mencionó anteriormente,ls -f
devuelve dos unidades adicionales, ya que también cuenta. Y ...).fuente
Solo agrego esto por completo. Por supuesto, otra persona ya ha publicado la respuesta correcta, pero también puede obtener un recuento de archivos y directorios con el programa de árbol.
Ejecute el comando
tree | tail -n 1
para obtener la última línea, que dirá algo así como "763 directorios, 9290 archivos". Esto cuenta los archivos y carpetas de forma recursiva, excluyendo los archivos ocultos, que se pueden agregar con la bandera-a
. Como referencia, tardé 4,8 segundos en mi computadora, para que el árbol contara todo mi directorio de inicio, que era 24777 directorios, 238680 archivos.find -type f | wc -l
tardó 5.3 segundos, medio segundo más, así que creo que el árbol es bastante competitivo en cuanto a velocidad.Mientras no tenga ninguna subcarpeta, el árbol es una forma rápida y fácil de contar los archivos.
Además, y solo por el gusto de hacerlo, puede usar
tree | grep '^├'
para mostrar solo los archivos / carpetas en el directorio actual; esta es básicamente una versión mucho más lenta dels
.fuente
Brew install tail
para OS X.tail
ya debería estar instalado en su sistema Mac OS X.Recuento rápido de archivos de Linux
El recuento de archivos de Linux más rápido que conozco es
¡No hay necesidad de invocar grep! Pero como se mencionó, debe tener una base de datos nueva (actualizada diariamente por un trabajo cron o manual por
sudo updatedb
).Desde el hombre localizar
¡Además , debe saber que también cuenta los directorios como archivos!
Por cierto: si desea una descripción general de sus archivos y directorios en su tipo de sistema
Produce el número de directorios, archivos, etc.
fuente
Escribir esto aquí ya que no tengo suficientes puntos de reputación para comentar una respuesta, pero se me permite dejar mi propia respuesta, lo que no tiene sentido. De todas formas...
Sobre la respuesta de Christopher Schultz , sugiero cambiar stat a lstat y posiblemente agregar una verificación de límites para evitar el desbordamiento del búfer:
La sugerencia de usar lstat es evitar seguir enlaces simbólicos que podrían conducir a ciclos si un directorio contiene un enlace simbólico a un directorio padre.
fuente
lstat
fue una buena sugerencia y mereces karma por ello. Esta sugerencia se incorporó a mi código publicado anteriormente y, ahora, en GitHub.Podrías probar si usar
opendir()
ereaddir()
inPerl
es más rápido. Para ver un ejemplo de esas funciones, mira aquífuente
Esta respuesta aquí es más rápida que casi todo lo demás en esta página para directorios muy grandes y muy anidados:
https://serverfault.com/a/691372/84703
locate -r '.' | grep -c "^$PWD"
fuente
locate -c -r '/path'
como en la solución deVine aquí cuando trataba de contar los archivos en un conjunto de datos de ~ 10K carpetas con ~ 10K archivos cada una. El problema con muchos de los enfoques es que implícitamente almacenan archivos de 100M, lo que lleva años.
Me tomé la libertad de extender el enfoque por Christopher-Schultz para que sea compatible con el paso de directorios a través de args (su enfoque recursivo también usa stat).
Ponga lo siguiente en el archivo
dircnt_args.c
:Después de un
gcc -o dircnt_args dircnt_args.c
puede invocarlo así:En archivos de 100M en carpetas de 10K, lo anterior se completa bastante rápido (~ 5 min para la primera ejecución, seguimiento en caché: ~ 23 s).
El único otro enfoque que terminó en menos de una hora era ls con alrededor de 1 min en cache:
ls -f /your/dirs/* | wc -l
. Sin embargo, el recuento está apagado por un par de nuevas líneas por directorio ...Aparte de lo esperado, ninguno de mis intentos con
find
regresó en una hora: - /fuente
La forma más rápida en Linux (la pregunta está etiquetada como Linux), es utilizar la llamada directa al sistema. Aquí hay un pequeño programa que cuenta archivos (solo, sin directorios) en un directorio. Puede contar millones de archivos y es aproximadamente 2.5 veces más rápido que "ls -f" y aproximadamente 1.3-1.5 veces más rápido que la respuesta de Christopher Schultz.
PD: No es recursivo, pero puedes modificarlo para lograrlo.
fuente
opendir
/readdir
, pero sospecho que al final se reduce a casi el mismo código. Hacer llamadas al sistema de esa manera tampoco es portátil y, como Linux ABI no es estable, un programa compilado en un sistema no garantiza que funcione correctamente en otro (aunque es un buen consejo compilar cualquier cosa desde la fuente en cualquier * NIX system IMO ) Si la velocidad es clave, esta es una buena solución si realmente mejora la velocidad: no he comparado los programas por separado.ls
pasa más tiempo ordenando los nombres de los archivos, usar-f
para deshabilitar la ordenación ahorrará alguna vez:o puedes usar
find
:fuente
Me di cuenta de que no usar el procesamiento de memoria cuando tienes una gran cantidad de datos es más rápido que "canalizar" los comandos. Así que guardé el resultado en un archivo y luego lo analicé
fuente
Debe usar "getdents" en lugar de ls / find
Aquí hay un muy buen artículo que describe el enfoque de getdents.
http://be-n.com/spw/you-can-list-a-million-files-in-a-directory-but-not-with-ls.html
Aquí está el extracto:
ls y prácticamente cualquier otro método para enumerar un directorio (incluido python os.listdir, find.) confía en libc readdir (). Sin embargo, readdir () solo lee 32K de entradas de directorio a la vez, lo que significa que si tiene muchos archivos en el mismo directorio (es decir, 500M de entradas de directorio) tomará un tiempo increíblemente largo leer todas las entradas de directorio , especialmente en un disco lento. Para los directorios que contienen una gran cantidad de archivos, deberá profundizar más que las herramientas que dependen de readdir (). Deberá usar la llamada al sistema getdents () directamente, en lugar de los métodos auxiliares de libc.
Podemos encontrar el código C para enumerar los archivos usando getdents () desde aquí :
Debe realizar dos modificaciones para enumerar rápidamente todos los archivos en un directorio.
Primero, aumente el tamaño del búfer de X a algo así como 5 megabytes.
Luego modifique el bucle principal donde imprime la información sobre cada archivo en el directorio para omitir las entradas con inode == 0. Lo hice agregando
En mi caso, también solo me preocupaban los nombres de archivo en el directorio, así que también reescribí la declaración printf () para imprimir solo el nombre del archivo.
Compílelo (no necesita ninguna biblioteca externa, por lo que es muy sencillo de hacer)
Ahora solo corre
fuente
readdir()
lo que en realidad no es lento. Necesito una figura sólida antes de creer que vale la pena tirar la portabilidad para este aumento de rendimiento.Prefiero el siguiente comando para realizar un seguimiento de los cambios en la cantidad de archivos en un directorio.
El comando mantendrá una ventana abierta para realizar un seguimiento del número de archivos que están en el directorio con una frecuencia de actualización de 0.1 segundos.
fuente
ls | wc -l
terminará para una carpeta con miles o millones de archivos en 0.01s? incluso suls
es enormemente ineficiente en comparación con otras soluciones. Y el OP solo quiere obtener el recuento, no sentado mirando el cambio de salidawatch
manual después de ese comentario y vi que 0.01s (no 0.1s) es un número poco realista porque la frecuencia de actualización de la mayoría de las pantallas de PC es de solo 60Hz, y esto no responde la pregunta de ninguna manera. El OP preguntó sobre "Recuento rápido de archivos de Linux para una gran cantidad de archivos". Tampoco leyó ninguna respuesta disponible antes de publicarPrimeros 10 directores con el mayor número de archivos.
fuente