2010-09-29 23 views
12
var fsw = new FileSystemWatcher(sPath, "*.PPF"); 
fsw.NotifyFilter = NotifyFilters.FileName; 
fsw.IncludeSubdirectories = true; 
fsw.Created += FswCreated; 
fsw.EnableRaisingEvents = true; 

static void FswCreated(object sender, FileSystemEventArgs e) 
{ 
    string sFile = e.FullPath; 
    string[] arrLines = File.ReadAllLines(sFile); 
} 

esto falla con archivos grandes, porque el proceso no está terminado con la escritura del archivo. El archivo se copia a través de la red, por lo que no sé el tamaño del archivo. ¿Qué tipo de sincronización se requiere para que esto sea sólido?vigilante del sistema de archivos y archivos de gran tamaño

+0

¿Cómo funciona? cual excepción? –

Respuesta

27

Solución encontrada en stackoverflow y modificada un poco.

static bool IsFileLocked(FileInfo file) 
{ 
    FileStream stream = null; 

    try 
    { 
     stream = file.Open(FileMode.Open, 
       FileAccess.ReadWrite, FileShare.None); 
    } 
    catch (IOException) 
    { 
     //the file is unavailable because it is: 
     //still being written to 
     //or being processed by another thread 
     //or does not exist (has already been processed) 
     return true; 
    } 
    finally 
    { 
     if (stream != null) 
      stream.Close(); 
    } 

    //file is not locked 
    return false; 
} 

static void FswCreated(object sender, FileSystemEventArgs e) 
{ 
    string sFile = e.FullPath; 

    Console.WriteLine("processing file : " + sFile); 

    // Wait if file is still open 
    FileInfo fileInfo = new FileInfo(sFile); 
    while(IsFileLocked(fileInfo)) 
    { 
     Thread.Sleep(500); 
    } 

    string[] arrLines = File.ReadAllLines(sFile); 
} 
+0

gracias por formatear mi artículo. ¿Dónde puedo encontrar el formato adecuado para mis preguntas futuras? – NickD

+0

Genial, pero si el archivo es de solo lectura, fallará. Es posible que desee abrir el archivo con el modo de acceso FileAccess.Read. – electricalbah

+0

true, thx para señalar. – NickD

0

Simplemente en su fswCreated, duerma durante aproximadamente 1/2 segundos con Thread.Sleep(500) si eso es posible. Eso debería darle el tiempo que la computadora necesita para terminar de escribir el archivo.

Por supuesto, para discos duros más lentos, esto puede o puede ser suficiente.

+0

esto no funcionará si el archivo es muy grande como en GBs. la solución es intentar leer el archivo en filestream y manejar la excepción io por Thread.Sleep e intentar leer el archivo nuevamente. ver mi respuesta a continuación – Thakur

4

Utilice la DelayedFileSystemWatcher.cs Clase http://blogs.msdn.com/b/ahamza/archive/2006/02/06/526222.aspx

y luego este código. Compruebe el controlador de eventos PrintFileSystemEventHandler. Intenta leer el archivo en la secuencia de archivos y, si se produce algún error, asume que el archivo todavía está leyendo, por lo que espera un intervalo (2 segundos en este ejemplo) y luego vuelve a intentarlo. Compruebe la etiqueta CONVERSION:

static void Main(string[] args) 
    { 
     DelayedFileSystemWatcher dfw = new DelayedFileSystemWatcher(@"C:\\Test", "*.*"); 
     dfw.Changed += new FileSystemEventHandler(Program.FileSystemEventHandlerMethod); 
     dfw.Created += new FileSystemEventHandler(Program.FileSystemEventHandlerMethod); 
     dfw.Deleted += new FileSystemEventHandler(Program.FileSystemEventHandlerMethod); 
     dfw.Error += new ErrorEventHandler(Program.ErrorEventHandlerMethod); 
     dfw.Renamed += new RenamedEventHandler(Program.RenamedEventHandlerMethod); 

     dfw.IncludeSubdirectories = true; 
     dfw.ConsolidationInterval = 1000; 
     dfw.EnableRaisingEvents = true; 
     Console.WriteLine("Press \'q\' to quit the sample."); 
     while (Console.Read() != 'q') ; 
     //System.Threading.Thread.Sleep(60000); 
     dfw.Dispose(); 
    } 
    private static void FileSystemEventHandlerMethod(object sender, FileSystemEventArgs e) 
    { 
     PrintFileSystemEventHandler(e); 
     System.Console.WriteLine(); 
    } 

    private static void ErrorEventHandlerMethod(object sender, ErrorEventArgs e) 
    { 
     System.Console.WriteLine(e.GetException().Message); 
     System.Console.WriteLine(); 
    } 

    private static void RenamedEventHandlerMethod(object sender, RenamedEventArgs e) 
    { 
     PrintRenamedEventHandler(e); 
     System.Console.WriteLine(); 
    } 

    private static void PrintFileSystemEventHandler(FileSystemEventArgs e) 
    { 

    CONVERSION: 
     try 
     { 

      if (e.ChangeType != WatcherChangeTypes.Deleted) 
      { 
       if (!isFolder(e.FullPath) && isFile(e.FullPath)) 
       { 
        FileStream fs = new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.None); 
        fs.Close(); 
       } 

      } 
      System.Console.WriteLine(e.Name + " " + e.FullPath + " " + e.ChangeType); 

     } 
     catch (System.IO.IOException) 
     { 
      Console.WriteLine("There was an IOException error or File is still copying. Retrying in 2 seconds..."); 
      System.Threading.Thread.Sleep(2000); 
      goto CONVERSION; 
     } 



     //System.Console.WriteLine(e.Name); 
     //System.Console.WriteLine(e.FullPath); 
     //System.Console.WriteLine(e.ChangeType); 
    } 

    private static bool isFolder(string strPath) 
    { 

     bool isFolderExist = false; 
     try 
     { 
      isFolderExist = Directory.Exists(strPath); 
     } 
     catch 
     { 
      isFolderExist = false; 
     } 
     return isFolderExist; 
    } 

    private static bool isFile(string strPath) 
    { 

     bool isFileExist = false; 
     try 
     { 
      isFileExist = File.Exists(strPath); 
     } 
     catch 
     { 
      isFileExist = false; 
     } 
     return isFileExist; 
    } 


    private static void PrintRenamedEventHandler(RenamedEventArgs e) 
    { 
     PrintFileSystemEventHandler(e); 
     System.Console.WriteLine(e.OldName); 
     System.Console.WriteLine(e.OldFullPath); 
    } 

no tengo el enlace con el proyecto. pero esto ayudará.

+1

Puedo ver un 'goto' allí :) –

1

AFAIK no se le notificará una vez que se haya realizado la copia, puede implementar un mecanismo de reintento.
Si obtiene una violación de corte, active un temporizador para volver a intentar la operación en X segundos.
El segundo intento debe ser después de X * 2 segundos y así sucesivamente (con alguna limitación de curso).

2

Apoyo la solución aceptada por Shay Erlichmen. Pero sin embargo a) Puede wa no para abrir el archivo con el modo de acceso FileAccess.Read, en caso que es un archivo de sólo lectura

b) Algunos programas, mientras que la descarga, el archivo tendrá alguna extensión divertido y una vez terminado, la extensión cambiará, y aunque el archivo se habrá completado, tendrá una excepción de archivo no encontrado.

Controle las excepciones y suscríbase al evento file.renamed

Cuestiones relacionadas