Tengo que verificar si el directorio en el disco está vacío. Significa que no contiene ninguna carpeta / archivo. Sé que hay un método simple. Obtenemos una matriz de FileSystemInfo y verificamos si el recuento de elementos es igual a cero. Algo como eso:
public static bool CheckFolderEmpty(string path)
{
if (string.IsNullOrEmpty(path))
{
throw new ArgumentNullException("path");
}
var folder = new DirectoryInfo(path);
if (folder.Exists)
{
return folder.GetFileSystemInfos().Length == 0;
}
throw new DirectoryNotFoundException();
}
Este enfoque parece estar bien. ¡¡PERO!! Es muy, muy malo desde una perspectiva de rendimiento. GetFileSystemInfos () es un método muy difícil. En realidad, enumera todos los objetos del sistema de archivos de la carpeta, obtiene todas sus propiedades, crea objetos, llena la matriz escrita, etc. Y todo esto simplemente para verificar la longitud. Eso es estúpido, ¿no?
Acabo de perfilar dicho código y determiné que ~ 250 llamadas de dicho método se ejecutan en ~ 500ms. Esto es muy lento y creo que es posible hacerlo mucho más rápido.
¿Alguna sugerencia?
Respuestas:
Hay una nueva característica en
Directory
yDirectoryInfo
.NET 4 que les permite devolverIEnumerable
una matriz en lugar de una matriz, y comenzar a devolver resultados antes de leer todo el contenido del directorio.Directory.EnumerateFileSystemEntries
sobrecargas de métodoEDITAR: al ver esa respuesta nuevamente, me doy cuenta de que este código se puede hacer mucho más simple ...
fuente
EnumerateFileSystemEntries
, o usar.Any(condition)
(especifique la condición como una expresión lambda o como un método que toma una ruta como parámetro).return !items.GetEnumerator().MoveNext();
Aquí está la solución extra rápida, que finalmente implementé. Aquí estoy usando WinAPI y las funciones FindFirstFile , FindNextFile . Permite evitar la enumeración de todos los elementos en la carpeta y se detiene justo después de detectar el primer objeto en la carpeta . Este enfoque es ~ 6 (!!) veces más rápido que el descrito anteriormente. ¡250 llamadas en 36 ms!
Espero que sea útil para alguien en el futuro.
fuente
SetLastError = true
aDllImport
forFindFirstFile
para que laMarshal.GetHRForLastWin32Error()
llamada funcione correctamente, como se describe en la sección Comentarios del documento de MSDN para GetHRForLastWin32Error () .Podría intentar
Directory.Exists(path)
yDirectory.GetFiles(path)
, probablemente menos gastos generales (sin objetos, solo cadenas, etc.).fuente
Esta prueba rápida regresó en 2 milisegundos para la carpeta cuando estaba vacía y cuando contenía subcarpetas y archivos (5 carpetas con 5 archivos en cada una)
fuente
Lo uso para carpetas y archivos (no sé si es óptimo)
fuente
Si no le importa dejar C # puro e ir a las llamadas de WinApi , puede considerar la función PathIsDirectoryEmpty () . Según el MSDN, la función:
Esa parece ser una función que hace exactamente lo que quieres, por lo que probablemente esté bien optimizada para esa tarea (aunque no lo he probado).
Para llamarlo desde C #, el sitio pinvoke.net debería ayudarlo. (Desafortunadamente, todavía no describe esta determinada función, pero debería poder encontrar algunas funciones con argumentos similares y devolver el tipo allí y usarlas como base para su llamada. Si vuelve a buscar en el MSDN, dice que la DLL para importar es
shlwapi.dll
)fuente
No sé acerca de las estadísticas de rendimiento de este, pero ¿has intentado usar el
Directory.GetFiles()
método estático?Devuelve una matriz de cadena que contiene nombres de archivo (no FileInfos) y puede verificar la longitud de la matriz de la misma manera que anteriormente.
fuente
Estoy seguro de que las otras respuestas son más rápidas, y su pregunta preguntaba si una carpeta contenía o no archivos o carpetas ... pero creo que la mayoría de las veces la gente consideraría un directorio vacío si no contiene archivos. es decir, todavía está "vacío" para mí si contiene subdirectorios vacíos ... ¡esto puede no ser adecuado para su uso, pero puede ser para otros!
fuente
Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories).Any()
Tendrá que ir al disco duro para obtener esta información en cualquier caso, y esto solo superará cualquier creación de objetos y relleno de matriz.
fuente
Sin embargo, no conozco un método que le diga sucintamente si una carpeta determinada contiene otras carpetas o archivos, sin embargo, usando:
debería ayudar al rendimiento ya que estos dos métodos solo devolverán una matriz de cadenas con los nombres de los archivos / directorios en lugar de los objetos FileSystemInfo completos.
fuente
Gracias a todos por las respuestas. Traté de usar Directory.GetFiles () y Directory.GetDirectories () métodos . ¡Buenas noticias! ¡El rendimiento mejoró ~ dos veces! 229 llamadas en 221ms. Pero también espero que sea posible evitar la enumeración de todos los elementos de la carpeta. De acuerdo, que todavía se está ejecutando el trabajo innecesario. ¿No lo crees así?
Después de todas las investigaciones, llegué a la conclusión de que, bajo puro .NET, una optimización adicional es imposible. Voy a jugar con la función FindFirstFile de WinAPI . Espero que ayude.
fuente
En algún momento es posible que desee verificar si existen archivos dentro de los subdirectorios e ignorar esos subdirectorios vacíos; en este caso puedes usar el método a continuación:
fuente
Fácil y simple
fuente
Basado en el código de Brad Parks :
fuente
Mi código es increíble, solo tomó 00: 00: 00.0007143 menos de milisegundos con 34 archivos en la carpeta
fuente
Aquí hay algo que podría ayudarlo a hacerlo. Logré hacerlo en dos iteraciones.
fuente
Como de todos modos vas a trabajar con un objeto DirectoryInfo, iría con una extensión
fuente
Utilizar este. Es sencillo.
fuente