2010-10-05 14 views
5

planeo realizar un comando de lista estándar para obtener un vector o una lista del contenido de un directorio.La posibilidad más rápida de enumerar un directorio y obtener las direcciones URL de cada archivo en Java

Sé que esto es fácil mediante el uso

File f = new File("C:/testDir"); 
File[] files = f.listFiles(); 

El problema es que necesito una lista/matriz/vector de URLs. Así que mis pensamientos fueron convertir los archivos a URL. Con la biblioteca org.apache.commons.io.FileUtils esto es posible con el siguiente código simple:

URL[] urls = FileUtils.toURLs(files); 

Esto hace exactamente lo que necesito, pero por desgracia es muy lento (especialmente para los directorios con miles de archivos), aunque solo utiliza un for-loop y analiza cada objeto File con el método "toURL()".

¿Alguien sabe una manera de hacer esta tarea en un mejor rendimiento?

+0

Solo necesita una barra inclinada entre C: y testDir. –

+0

sí, tienes razón. Lo corrigió – Ahaggar

+1

Cada vez que usas un vector, un hada muere ... – Pablojim

Respuesta

8

La única optimización que es simple sería reducir la creación de objetos, lo que supondrá una modesta mejora en el rendimiento. En lugar de usar listFiles(), que crea una gran cantidad de objetos File, use list() para obtener una matriz String de solo los nombres de los archivos, no las rutas, y cree las URL directamente. La creación y el almacenamiento de cadenas tendrán menos sobrecarga de objetos en este caso. La manipulación de cuerdas obviamente podría hacerse más rápida y adecuada, aunque probablemente no suponga una gran diferencia.

Algo así como:

ArrayList<URL> urls = new ArrayList<URL>(); //or use an array if you prefer. 
for(String name: f.files()) 
    urls.add(new URL("file://"+f.getPath()+"/"+name)); 
+1

Gracias chicos por las respuestas. Esto parece ser simple y eficiente. Una primera prueba me dio una aceleración en el factor 5, testet con aproximadamente 4000 archivos. Pruebo un poco más y luego le doy un comentario – Ahaggar

+2

+1. Además, revisé esto y descubrí que usar el nuevo URL del constructor ("file", f.getPath(), name) aún mejora el rendimiento de este enfoque. –

+2

Puede obtener una pequeña ganancia al pasar el tamaño correcto cuando llama a ArrayList (files.size()); Esto evitará tener que reasignar la matriz subyacente en el bucle principal. –

1

Su solución está bien, y no debe preocuparse por el rendimiento, a menos que tenga decenas de miles de archivos en ese directorio.

Una optimización del rendimiento puede ser almacenar en caché la matriz de URL s si esta funcionalidad se usa mucho.

Dicho esto: mida cuánto se tarda en realizar esto en un directorio con 2k archivos, y luego optimice.

+0

Su pregunta dice que sí tiene miles de archivos: P – willcodejavaforfood

+0

En realidad, quería decir decenas de miles ... :) (para denotar un número grande) – Bozho

+0

tal vez no fue lo suficientemente preciso Tengo directorios desde 1000 hasta varias decenas de miles de archivos. – Ahaggar

1

Si realmente tiene tantos archivos es posible que desee utilizar varios hilos. Cada uno de los n hilos conversa con 1/n archivos.

Para que esto sea eficiente necesita realmente muchos archivos.

2

crear un nuevo objeto URL, en lugar de invocar el método toUrl() parece ser más eficiente. He comprobado esto:

File parent=new File("./doc"); 
    File[] listado=parent.listFiles(); 
    long t0=0L; 
    try { 
     t0=System.currentTimeMillis(); 
     for(int k=0;k<10000;k++) { 
     URL[] listaArchivos=new URL[listado.length]; 
     for (int i = 0; i < listado.length; i++) { 
      listaArchivos[i]=listado[i].toURL(); 
     } 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    System.out.println("Files:"+listado.length+"; Time 1: "+(System.currentTimeMillis()-t0)+" ms"); 


    try { 
     t0=System.currentTimeMillis(); 
     for(int k=0;k<10000;k++) { 
      URL[] listaArchivos=new URL[listado.length]; 
      for (int i = 0; i < listado.length; i++) { 
       listaArchivos[i]=new URL("file://"+listado[i].getAbsolutePath()); 
      } 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    }   
    System.out.println("Files:"+listado.length+"; Time 2: "+(System.currentTimeMillis()-t0)+" ms"); 

Mi salida es:

Files:14; Time 1: 1985 ms 
Files:14; Time 2: 516 ms 
+1

¿Es lo mismo si ejecuta su segundo algoritmo primero? Solo para asegurarse, el segundo algoritmo no se beneficia de algunos chaches internos ... –

+0

@Andreas_D No había pensado en esto: vamos a comprobarlo. –

+0

@Andreas_D: Listo. Ahora escribe Archivos: 14; Hora 2: 532 ms Archivos: 14; Tiempo 1: 1937 ms. Entonces, el enfoque de "nueva URL (cadena)" sigue siendo más rápido. Para mi sorpresa, debo decir. –

1

Otras personas han respondido diciendo que la construcción de las direcciones URL mediante la concatenación de cadenas (por ejemplo "file://" + dirPath + "/" + file.getName() es mucho más rápido que llamar File.toURI().toString() Por ejemplo. el OP informa una aceleración 5 veces. Me pregunté por qué hay tal diferencia.

Aparentemente, una razón es que el método toURI() comprueba si this es un directorio, y agrega un / si lo es. El corolario es que una URL para un directorio producido por la concatenación de cadenas no tendrá con un / posterior.

Hay otra advertencia al crear "file:" URL por concatenación de cadenas. Es decir que si los nombres en la ruta del archivo contienen caracteres reservados (según las especificaciones de URL/URI), la concatenación de cadenas puede producir una URL/URI mal formada. Los caracteres reservados normalmente deben ser % escapado. Además, en Windows no está del todo claro cómo deberían representarse las letras de unidad en las URL "file:".

Cuestiones relacionadas