2009-03-26 24 views
48

¿Cómo calculo el número de archivos en un directorio utilizando Java? Para simplificar, supongamos que el directorio no tiene ningún subdirectorio.Contar el número de archivos en un directorio utilizando Java

Sé que el método estándar de:

new File(<directory path>).listFiles().length 

pero esto va a ir con eficacia a través de todos los archivos en el directorio, lo que puede tardar mucho tiempo si el número de archivos es grande. Además, no me importan los archivos reales en el directorio a menos que su número sea mayor que un número grande fijo (digamos 5000).

estoy adivinando, pero no el directorio (o su i-nodo en caso de Unix) almacenar el número de archivos contenidos en ella? Si pudiera obtener ese número directamente del sistema de archivos, sería mucho más rápido. Necesito hacer esta comprobación para cada solicitud HTTP en un servidor Tomcat antes de que el back-end comience a hacer el procesamiento real. Por lo tanto, la velocidad es de suma importancia.

que podría ejecutar un demonio de vez en cuando para limpiar el directorio. Lo sé, así que por favor no me des esa solución.

+0

Si el directorio tiene potencialmente una gran cantidad de archivos (1000s +), es posible que desee evitar asignar la matriz devuelta por los métodos de la lista de archivos. No he intentado esto todavía, pero tal vez podría usar listFiles y pasarle una instancia de FileFilter que hace el conteo de los archivos en el método accept, mientras que al mismo tiempo devuelve false para todos los archivos. Supongo que esto evita la asignación de la matriz, al tiempo que le da un recuento de archivos. –

+0

Ignore mi último comentario ... Dependiendo de la impl JDK, la matriz se puede asignar de todos modos (debajo del capó).Ese parece ser el caso en openjdk de todos modos. –

+0

Para Java 7 y versiones posteriores, este problema tiene una buena solución con una API Java estándar. Consulte la respuesta de @ mateuscb a continuación - http://stackoverflow.com/questions/687444/counting-the-number-of-files-in-a-directory-using-java/30784016#30784016. –

Respuesta

9

Esto podría no ser apropiada para su aplicación, pero siempre se puede hacer una llamada nativa (JNI utilizando o jna) o exec un comando específico de la plataforma y leer la salida antes de caer de nuevo a la lista(). Longitud. En * nix, podría ejecutar ls -1a | wc -l (nota: eso es dash-one-a para el primer comando, y dash-minúscula-L para el segundo). No estoy seguro de lo que sería correcto en Windows, tal vez solo un dir y busque el resumen.

Antes de molestar con algo como esto te recomiendo encarecidamente que crea un directorio con un número muy grande de archivos y acaba de ver si la lista(). Longitud realmente necesita demasiado tiempo. Como this blogger sugiere, es posible que no desee sudar esto.

probablemente me vaya con la respuesta de Varkhan mí mismo.

+1

¿'A' es apropiado en el caso de la solución 'ls'? ¿No sería eso también una lista '.' y' ..'? –

+0

Y creo que es posible que desee una '-f' si hay muchos archivos en el directorio, de lo contrario, la mayor parte del tiempo se utilizará en la clasificación predeterminada. – Glenn

15

Desafortunadamente, creo que ya es la mejor manera (aunque list() es ligeramente mejor que listFiles(), ya que no construye objetos File).

67

Ah ... la razón para no tener un método sencillo en Java para hacer eso es la abstracción de almacenamiento de archivos: algunos sistemas de archivos pueden no tener el número de archivos en un directorio disponible ... ese recuento puede no tener ninguno significado en absoluto (ver, por ejemplo, sistemas de archivos distribuidos, P2P, fs que almacenan listas de archivos como una lista vinculada, o sistemas de archivos respaldados por bases de datos ...). Así que sí,

new File(<directory path>).list().length 

es probablemente su mejor apuesta.

+0

IMO, eso no justifica no tener dicho método; simplemente podría devolver nulo para FS donde N/A. Los FSs exóticos no son motivo para perder ciclos al obtener una matriz. –

+0

Eso no tiene sentido para mí. ¿Por qué puedes obtener todos los archivos y contarlos pero no solo obtener el conteo? ¿Dónde está la diferencia? –

1

Por desgracia, como decían mmyers, File.list() es casi tan rápido como se va a conseguir el uso de Java. Si la velocidad es tan importante como dices, puedes considerar realizar esta operación en particular usando JNI. A continuación, puede adaptar su código a su situación particular y sistema de archivos.

3

Si tiene directorios que contienen realmente (> 100.000) muchos archivos, aquí es una manera (no portátil) para ir:

String directoryPath = "a path"; 

// -f flag is important, because this way ls does not sort it output, 
// which is way faster 
String[] params = { "/bin/sh", "-c", 
    "ls -f " + directoryPath + " | wc -l" }; 
Process process = Runtime.getRuntime().exec(params); 
BufferedReader reader = new BufferedReader(new InputStreamReader(
    process.getInputStream())); 
String fileCount = reader.readLine().trim(); 
reader.close(); 
System.out.println(fileCount); 
2

Usando sigar debe ayudar.Sigar tiene ganchos nativos para obtener las estadísticas

new Sigar().getDirStat(dir).getTotal() 
+0

¿Desempeño? ¿Memoria? ¿Gastos generales? – Antares42

5

Puesto que usted no necesita realmente el número total, y de hecho quieren realizar una acción después de un cierto número (en su caso 5000), puede utilizar java.nio.file.Files.newDirectoryStream. El beneficio es que puede salir temprano en lugar de tener que pasar por todo el directorio solo para obtener un conteo.

public boolean isOverMax(){ 
    Path dir = Paths.get("C:/foo/bar"); 
    int i = 1; 

    try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) { 
     for (Path p : stream) { 
      //larger than max files, exit 
      if (++i > MAX_FILES) { 
       return true; 
      } 
     } 
    } catch (IOException ex) { 
     ex.printStackTrace(); 
    } 

    return false; 
} 

El interface doc de DirectoryStream también tiene algunos buenos ejemplos.

23

Desde Java 8, se puede hacer eso en una línea:

Files.list(Paths.get("your/path/here")).count(); 

En cuanto a los 5000 nodos secundarios y aspectos de nodo-i:

Este método iterar sobre las entradas, pero como se sugiere Varkhan es probable que pueda No lo harás mejor además de jugar con JNI o ​​dirigir llamadas de comandos del sistema, ¡pero aun así, nunca puedes estar seguro de que estos métodos no hagan lo mismo!

Sin embargo, vamos a profundizar en esto un poco:

En cuanto a la fuente JDK8, Files.list expone una corrienteque utiliza un Iterable de Files.newDirectoryStream que los delegados a FileSystemProvider.newDirectoryStream.

En los sistemas UNIX (descompilado sun.nio.fs.UnixFileSystemProvider.class), carga un iterador: se usa un sun.nio.fs.UnixSecureDirectoryStream (con bloqueos de archivos mientras se itera en el directorio).

Entonces, hay un iterador que recorrerá las entradas aquí.

Ahora, veamos el mecanismo de conteo.

El recuento real se realiza mediante la API de reducción de recuento/suma expuesta por Java 8 streams. En teoría, esta API puede realizar operaciones paralelas sin mucho esfuerzo (con multihtreading). Sin embargo, la corriente se crea con el paralelismo desactivado por lo que es un no ir ...

El lado bueno de este enfoque es que no se carga la matriz en la memoria que las entradas serán contados por un iterador tal como los lee la API subyacente (Sistema de archivos).

Por último, para la información, conceptualmente en un sistema de archivos, un nodo de directorio no es necesario para mantener la número de los archivos que contiene, puede simplemente contener la lista de los que es nodos secundarios (lista de nodos) No soy un experto en sistemas de archivos, pero creo que los sistemas de archivos UNIX funcionan así. Por lo tanto, no puede suponer que hay una forma de tener esta información directamente (es decir: siempre puede haber una lista de nodos secundarios ocultos en algún lugar).

+2

Java 8 'Files.list()' arroja 'IOException'; el método 'list()' de la clase 'File' no arroja ninguna excepción. –

+0

He estado usando '' Files.list() '' para un directorio con 1-2 millones de archivos, y por supuesto toma un tiempo. Pero tengo la sensación de que esto está detrás de algunas excepciones generales de GC que he encontrado, porque millones de objetos de archivos se instancian y se destruyen para cada llamada. Todavía estoy buscando un método de rendimiento y seguro para la memoria ... – Antares42

Cuestiones relacionadas