2011-05-08 57 views
40

Me gustaría comprobar si el directorio está vacío en Java. Pero existe la posibilidad de que haya muchos archivos en ese directorio, así que me gustaría hacerlo sin consultar su lista de archivos, si es posible.Cómo comprobar si un directorio está vacío en Java

+0

lista() puede ser muy lento en muchos archivos. –

+3

¿Cuántos archivos puede haber allí? ¿Realmente has encontrado problemas de rendimiento? – RonK

+1

Al escanear directorios vacíos, encontré que .list() ocupaba más del 50% del tiempo de ejecución. Por lo tanto, encontrar una alternativa podría acelerar significativamente las cosas si realmente no necesita la lista de archivos. – cottonBallPaws

Respuesta

54

Con JDK7 puede usar Files.newDirectoryStream para abrir el directorio y luego usar el método hasNext() del iterador para probar que hay algún archivo para iterar (no olvide cerrar la secuencia). Esto debería funcionar mejor para directorios enormes o donde el directorio está en un sistema de archivos remoto en comparación con los métodos de la lista java.io.File.

Ejemplo:

private static boolean isDirEmpty(final Path directory) throws IOException { 
    try(DirectoryStream<Path> dirStream = Files.newDirectoryStream(directory)) { 
     return !dirStream.iterator().hasNext(); 
    } 
} 
+0

¿Cómo funcionaría si uno quisiera iterar sobre dirStream después del control? Intenté: for (Path artefact: dirStream) { Pero obtuve un Iterator ya obtenido - Excepción – garyee

4

Esto es una solución sucia, pero puede intentar eliminarlo (con el método delete), y si la operación de eliminación falla, entonces el directorio no está vacío, si tiene éxito, entonces está vacío (pero tiene para volver a crearlo, y eso no es limpio). Continuaré buscando una mejor solución.

EDITAR: he encontrado walkFileTree de la clase java.nio.file.Files: http://download.java.net/jdk7/docs/api/java/nio/file/Files.html#walkFileTree(java.nio.file.Path, java.nio.file.FileVisitor) problema es que se trata de Java 7 solamente.

He buscado S.O. para otras preguntas relacionadas con este mismo problema (enumerar archivos en un directorio sin usar la lista() que asigna memoria para una gran matriz) y la respuesta es bastante "no se puede, a menos que use JNI", que es a la vez plataforma dependiente y fea.

+0

Más o menos una respuesta +1. – asgs

+14

La eliminación del directorio puede fallar debido a otras causas, por ejemplo, permisos de archivos. –

+1

De hecho, es feo. Espero que haya una solución 100% Java para hacer esto. Sigue buscando. – gd1

3

Si puede vivir con el código dependiente de la plataforma, puede intentar usar el código nativo actual cargando una biblioteca del sistema y usando sus API.

En Windows, por ejemplo, que tienen un Win32 API llamado FindFirstFile() con el nombre del directorio ( sin una barra diagonal inversa). Si devuelve algo que no sea . y .., sabrá que el directorio no está vacío. No mostrará todos los archivos, por lo que es mucho más rápido que file.list().

El equivalente en Unix es opendir. Para sus propósitos, la lógica sería la misma.

Por supuesto, llamar a métodos nativos tiene un precio en la usabilidad y la carga inicial de la biblioteca que debería ser negada para cuando se ahorre en las consultas de FS.

+1

Teniendo en cuenta que no hay absolutamente nada que impida a las personas crear archivos que no contengan un "." y nada que impida que las personas creen directorios que contengan un "." - Esa solución no servirá de nada. Y aunque estoy seguro de que hay una manera más o menos eficiente de hacer esto con una API nativa, la sobrecarga de llamarlo, probablemente será peor. Dependiendo de la implementación de FS, es concebible que el sistema operativo tenga que enumerar todos los archivos para comenzar de todos modos (¿no tiene idea de cómo se implementa NTFS?) – Voo

+0

@Voo: el uso correcto es ignorar el '.' y' ..' entradas. Si un sistema de archivos no le permite obtener la primera entrada de directorio sin enumerar todos los archivos, no habría una forma rápida de verificar si está vacío, pero dudo que tal sistema de archivos exista alguna vez. – Gabe

+0

@Gabe Sí, no tengo idea de cómo se implementa NTFS en detalle. Su solución editada debería ser exactamente lo que quiere el OP, aparte del hecho de que es nativo, y supongo que el directorio debe ser bastante grande para compensar el costo de la llamada nativa (pero ya lo mencionó y la pregunta es sobre grandes directorios de todos modos, así que está bien también). Aunque deberías haber creado una nueva publicación (la editada no tiene mucho en común con la original;)), me gustaría invitar a subir tu publicación (¿o recibes una parte del crédito debido a tu edición?) – Voo

8

Teniendo en cuenta desde java.io.Filesource code, list() método hace:

public java.lang.String[] list() { 
    ... 
     byte[][] implList = listImpl(bs); 
     if (implList == null) { 
      // empty list 
      return new String[0]; 
     }  
    ... 
    } 

    private synchronized static native byte[][] listImpl(byte[] path); 

Se invoca a un método nativo que pasa una matriz de bytes para obtener los archivos de la misma. Si un método devuelve null, significa que el directorio está vacío.

Lo que significa, que no tienen ni siquiera un método nativo, para comprobar el vacío directorio sin el listado de archivos, por lo que no hay manera de que tendrían una implementación en Java para comprobar si el directorio está vacío.

Resultado: comprobar si el directorio está vacío sin listar archivos aún no está implementado en java.

2
 Path checkIfEmpty=Paths.get("Pathtofile"); 
    DirectoryStream<Path> ds = Files.newDirectoryStream(checkIfEmpty); 
    Iterator files = ds.iterator(); 
    if(!files.hasNext()) 
     Files.deleteIfExists(Paths.get(checkIfEmpty.toString())); 
+5

Solo tenga cuidado de cerrar DirectoryStream cuando termine (o use try-with-resources) de lo contrario terminará con una pérdida de controlador de archivos . – user194715

11
File parentDir = file.getParentFile(); 
if(parentDir.isDirectory() && parentDir.list().length == 0) { 
    LOGGER.info("Directory is empty"); 
} else { 
    LOGGER.info("Directory is not empty"); 
} 
3
if(!Files.list(Paths.get(directory)).findAny().isPresent()){ 
    Files.delete(Paths.get(directory)); 
} 

Como files.list devolver una secuencia perezosamente poblada que va a resolver su problema de tiempo de ejecución relacionados.

-1

También tuve esta confusión durante un tiempo largo sobre cómo comprobar si el Directorio estaba vacía o no Pero la respuesta es bastante simple uso

class isFileEmpty{ 
public static void main(String args[]){ 
File d = new File(//Path of the Directory you want to check or open); 
String path = d.getAbsolutePath().toString(); 
File dir = new File(path); 
File[] files = dir.listFiles(); 
if(!dir.exists()){ 
System.out.Println("Directory is Empty"); 
} 
else{ 
for(int i =0;i<files.length;i++){ 
System.out.Println(files[i]) 
      } 
     } 
    } 
} 
Cuestiones relacionadas