Pregunta

Tengo un archivo .csv que se actualiza con frecuencia (entre 20 y 30 veces por minuto).Quiero insertar las líneas recién agregadas en una base de datos tan pronto como se escriban en el archivo.

El Vigilante del sistema de archivos La clase escucha las notificaciones de cambios del sistema de archivos y puede generar un evento cada vez que hay un cambio en un archivo específico.El problema es que FileSystemWatcher no puede determinar exactamente qué líneas se agregaron o eliminaron (hasta donde yo sé).

Una forma de leer esas líneas es guardar y comparar el recuento de líneas entre los cambios y leer la diferencia entre el último y el penúltimo cambio.Sin embargo, estoy buscando una solución más limpia (quizás más elegante).

¿Fue útil?

Solución

He escrito algo muy similar.Utilicé FileSystemWatcher para recibir notificaciones sobre cambios.Luego utilicé FileStream para leer los datos (realizando un seguimiento de mi última posición dentro del archivo y buscándola antes de leer los nuevos datos).Luego agrego los datos leídos a un búfer que extrae automáticamente líneas completas y luego las envía a la interfaz de usuario.

Nota:"this.MoreData(..) es un evento, cuyo oyente se suma al búfer antes mencionado y maneja la extracción de línea completa.

Nota:Como ya se mencionó, esto sólo funcionará si las modificaciones son siempre adiciones al archivo.Cualquier eliminación causará problemas.

Espero que esto ayude.

   public void File_Changed( object source, FileSystemEventArgs e )
    {
        lock ( this )
        {
            if ( !this.bPaused )
            {
                bool bMoreData = false;

                // Read from current seek position to end of file
                byte[] bytesRead = new byte[this.iMaxBytes];
                FileStream fs = new FileStream( this.strFilename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite );

                if ( 0 == this.iPreviousSeekPos )
                {
                    if ( this.bReadFromStart )
                    {
                        if ( null != this.BeginReadStart )
                        {
                            this.BeginReadStart( null, null );
                        }
                        this.bReadingFromStart = true;
                    }
                    else
                    {
                        if ( fs.Length > this.iMaxBytes )
                        {
                            this.iPreviousSeekPos = fs.Length - this.iMaxBytes;
                        }
                    }
                }

                this.iPreviousSeekPos = (int)fs.Seek( this.iPreviousSeekPos, SeekOrigin.Begin );
                int iNumBytes = fs.Read( bytesRead, 0, this.iMaxBytes );
                this.iPreviousSeekPos += iNumBytes;

                // If we haven't read all the data, then raise another event
                if ( this.iPreviousSeekPos < fs.Length )
                {
                    bMoreData = true;
                }

                fs.Close();

                string strData = this.encoding.GetString( bytesRead );
                this.MoreData( this, strData );

                if ( bMoreData )
                {
                    File_Changed( null, null );
                }
                else
                {
                    if ( this.bReadingFromStart )
                    {
                        this.bReadingFromStart = false;
                        if ( null != this.EndReadStart )
                        {
                            this.EndReadStart( null, null );
                        }
                    }
                }
            }
        }

Otros consejos

Bien, FileSystemWatcher no sabe nada sobre el contenido de su archivo.Te dirá si cambió, etc.pero no lo que cambió.

¿Solo estás agregando al archivo?No estaba un poco claro en la publicación si se agregaron líneas o si también se podrían eliminar.Suponiendo que se agreguen, la solución es bastante sencilla; de lo contrario, tendrás que hacer algunas comparaciones.

Creo que deberías usar NTFS Change Journal o similar:

NTFS utiliza el diario de cambio para proporcionar un registro persistente de todos los cambios realizados en archivos en el volumen.Para cada volumen, NTFS utiliza el diario de cambio para rastrear información sobre archivos agregados, eliminados y modificados.La revista de cambios es mucho más eficiente que las marcas de tiempo o las notificaciones de archivos para determinar los cambios en un espacio de nombres determinado.

Puedes encontrar un descripción en TechNet.Necesitará utilizar PInvoke en .NET.

Mantendría el texto actual en la memoria si es lo suficientemente pequeño y luego usaría un algoritmo de diferenciación para verificar si el texto nuevo y el texto anterior cambiaron.Esta biblioteca, http://www.mathertel.de/Diff/, no sólo le dirá que algo cambió sino también qué cambió.Entonces puede insertar los datos modificados en la base de datos.

fuera de mi cabeza, podrías almacenar el último tamaño de archivo conocido.Verifique el tamaño del archivo y, cuando cambie, abra un lector.

Luego busque el lector hasta el último tamaño de archivo y comience a leer desde allí.

Tienes razón sobre FileSystemWatcher.Puede escuchar archivos creados, modificados, eliminados, etc.eventos pero no profundizas más que el archivo que los generó.

¿Tiene control sobre el archivo en sí?Podrías cambiar ligeramente el modelo para usar el archivo como un búfer.En lugar de un archivo, tenga dos.Uno es la puesta en escena, el otro es la suma de toda la producción procesada.Lea todas las líneas de su archivo "búfer", procéselas y luego insértelas al final de otro archivo que sea el total de todas las líneas procesadas.Luego, elimine las líneas que procesó.De esta manera, toda la información de su expediente quedará pendiente de procesamiento.El problema es que si el sistema no es de escritura (es decir,también elimina líneas), entonces no funcionará.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top