2010-12-04 8 views
12

Esto es una idea remota, ¿pero hay una forma más rápida de obtener tamaño, tiempo de lastacceso, tiempo de última creación, etc. para múltiples archivos?¿Forma más rápida de obtener múltiples FileInfo?

Tengo una larga lista de rutas de archivos (así que no necesito enumerarlas) y necesito buscar esa información lo más rápido posible. Crear archivos de información en paralelo probablemente no ayude mucho ya que el cuello de botella debería ser el disco.

El Diario NTFS solo mantiene los nombres de los archivos por desgracia, de lo contrario, "será genial, supongo que el sistema operativo no almacena esa meta información en algún lugar".

Otra optimización que podría hacerse si hay una llamada estática o Win32 (métodos de archivos sólo se permite que consiga una pieza de información a la vez, aunque) método que obtiene la información más bien que la creación de un grupo de FileInfo objetos

de todas formas, contento si alguien sabe algo que podría ayudar, por desgracia, tiene que tener que hacer la optimización de micro aquí y no "el uso de una base de datos" no es una respuesta viable;)

+0

Eche un vistazo a FluentPath disponible a través de NuGet. http://weblogs.asp.net/bleroy/archive/2010/11/19/fluentpath-1-0.aspx – jvanrhyn

+0

Según tengo entendido, es una mejor biblioteca para trabajar con rutas de archivos y operaciones de estilo linq y no mucho que ver con los metadatos de archivos bajo el capó – Homde

+0

Si no lo hay, ¿puede guardar en caché la información al principio del ciclo de vida de sus aplicaciones? Eso hará que la información esté disponible para usted en la memoria RAM, pero no estará actualizada si tiene una aplicación de larga ejecución. – Patrick

Respuesta

8

hay métodos estáticos en System.IO.File para conseguir lo que desea. Es una micro-optimización, pero podría ser lo que necesita: GetLastAccessTime, GetCreationTime.

Editar

dejaré el texto anterior porque usted pidió específicamente para los métodos estáticos. Sin embargo, creo que es mejor que utilices FileInfo (debes medir solo para estar seguro). Tanto File como FileInfo utiliza un método interno en File llamado FillAttributeInfo para obtener los datos que está buscando. Para las propiedades que necesita, FileInfo necesitará llamar a este método una vez. File tendrá que invocarlo en cada llamada, ya que el objeto de información de atributo se descarta cuando finaliza el método (ya que es estático).

Así que mi corazonada es que cuando necesite múltiples atributos, un FileInfo para cada archivo será más rápido. ¡Pero en situaciones de rendimiento, siempre debes medir! Enfrentado con este problema, probaría ambas opciones administradas como se describe anteriormente y haré un punto de referencia, tanto cuando se ejecute en serie como en paralelo. Entonces decide si es lo suficientemente rápido.

Si no es lo suficientemente rápido, debe recurrir directamente a la API de Win32. No sería demasiado difícil mirar File.FileAttributeInfo en las fuentes de referencia y encontrar algo similar.

segunda edición

De hecho, si realmente lo necesita, este es el código necesario para llamar a la API de Win32 directamente utilizando el mismo enfoque que el código interno para File no, pero mediante una llamada a un sistema operativo para obtener toda los atributos. Creo que solo deberías usar si es realmente necesario. Tendrá que analizar desde FILETIME a una fecha de uso utilizable usted mismo, etc., para que pueda obtener más trabajo que hacer manualmente.

static class FastFile 
{ 
    private const int MAX_PATH = 260; 
    private const int MAX_ALTERNATE = 14; 

    public static WIN32_FIND_DATA GetFileData(string fileName) 
    { 
     WIN32_FIND_DATA data; 
     IntPtr handle = FindFirstFile(fileName, out data); 
     if (handle == IntPtr.Zero) 
      throw new IOException("FindFirstFile failed"); 
     FindClose(handle); 
     return data; 
    } 

    [DllImport("kernel32")] 
    private static extern IntPtr FindFirstFile(string fileName, out WIN32_FIND_DATA data); 

    [DllImport("kernel32")] 
    private static extern bool FindClose(IntPtr hFindFile); 


    [StructLayout(LayoutKind.Sequential)] 
    public struct FILETIME 
    { 
     public uint dwLowDateTime; 
     public uint dwHighDateTime; 
    } 
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
    public struct WIN32_FIND_DATA 
    { 
     public FileAttributes dwFileAttributes; 
     public FILETIME ftCreationTime; 
     public FILETIME ftLastAccessTime; 
     public FILETIME ftLastWriteTime; 
     public int nFileSizeHigh; 
     public int nFileSizeLow; 
     public int dwReserved0; 
     public int dwReserved1; 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)] 
     public string cFileName; 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_ALTERNATE)] 
     public string cAlternate; 
    } 
} 
+0

Sí, pero luego tengo que hacer 4 llamadas separadas que no deberían ser tan buenas si tiene que hacer disk-io para cada una. Sin embargo, solo estoy especulando, FileInfo podría hacer eso ... tratando de echarle un vistazo al código fuente – Homde

+0

@MattiasK, estás * asumiendo * que disk-io es obligatorio. Es posible que el sistema operativo haya almacenado en memoria caché grandes cantidades de metadatos en la memoria, lo que le permite responder a sus solicitudes sin tocar el disco. Has indicado que * tienes que * tener que micro-optimizar, ¿has verificado esto al determinar realmente cuánto tiempo lleva sin optimizar? =) – Rob

+0

De hecho, utilicé GetLastWriteTime en una vista dinámica ClearCase (unidad de red) y fue terriblemente lento. Parece que GetLastWriteTime llama a Win32 CreateFile para recuperar un identificador para obtener la información del archivo que también causó que el antivirus ingrese. Sin embargo, al usar FindFirstFile ClearCase simplemente devolvió la información del archivo en caché y esto fue por el factor 10 más rápido. Gracias por el código de copiado, también! – schletti2000

2

¿es posible utilizar la clase DirectoryInfo ?

DirectoryInfo d = new DirectoryInfo(@"c:\\Temp"); 
FileInfo[] f= d.GetFiles() 
+0

Ya tengo las rutas de archivos , volver a enumerarlos parece una pérdida y dudo que el método sea más rápido que simplemente crear el – Homde

+0

de fileinfo de lo que creo, necesitas ir a las llamadas api nativas o mejor puedes solicitarlo como una función en la versión futura en .net? – TalentTuner

+0

Gracias por esto. Parece ser más rápido que hacerlo por separado para cada archivo. – jreichert

4

. Las clases DirectoryInfo y FileInfo de .NET son increíblemente lentas en este aspecto, especialmente cuando se usan con recursos compartidos de red.

Si muchos de los archivos que se "escanean" están en el mismo directorio, obtendrás resultados mucho más rápidos (según la situación: por dimensiones más rápido) mediante las funciones FindFirstFile, FindNextFile y FindClose de la API de Win32. Esto es cierto incluso si tiene que solicitar más información que realmente necesita (por ejemplo, si solicita todos los archivos ".log" en un directorio, donde solo necesita el 75% de ellos).

En realidad, las clases de información de .NET también usan estas funciones API de Win32 internamente. Pero solo "remmeber" los nombres de los archivos. Cuando se solicita más información sobre un grupo de archivos (por ejemplo, LastModified), se realiza una solicitud separada (de red) para cada archivo, lo que hace que el tiempo sea un problema.

+0

que es interesante, me pregunto si hay alguna optimización para leer archivos secuenciales con findfirstfile/findnextfile en un directorio para archivos locales. También sería interesante saber si el sistema operativo almacena en caché metadatos como este – Homde

+4

Solucionado en 4.0 con DirectoryInfo.EnumerateFiles/Directories() –

0

Creo que está buscando la función GetFileAttributesEx (pinvoke.net link). Sin embargo, la clase FileInfo (o más bien, su clase base) usa esto internamente de todos modos, así que dudo que veas ninguna mejora en el rendimiento.

Cuestiones relacionadas