Чтение изменений в файле в режиме реального времени с использованием .NET - PullRequest
3 голосов
/ 17 сентября 2008

У меня есть CSV-файл, который часто обновляется (примерно от 20 до 30 раз в минуту). Я хочу вставить вновь добавленные строки в базу данных, как только они будут записаны в файл.

Класс FileSystemWatcher прослушивает уведомления об изменениях файловой системы и может вызывать событие при каждом изменении в указанном файле. Проблема в том, что FileSystemWatcher не может точно определить, какие строки были добавлены или удалены (насколько я знаю).

Один из способов прочитать эти строки - сохранить и сравнить количество строк между изменениями и прочитать разницу между последним и вторым последним изменением. Однако я ищу более чистое (возможно, более элегантное) решение.

Ответы [ 6 ]

3 голосов
/ 17 сентября 2008

Я написал нечто очень похожее. Я использовал FileSystemWatcher для получения уведомлений об изменениях. Затем я использовал FileStream для чтения данных (отслеживая мою последнюю позицию в файле и просматривая ее перед чтением новых данных). Затем я добавляю прочитанные данные в буфер, который автоматически извлекает полные строки, а затем выводит их в пользовательский интерфейс.

Примечание: "this.MoreData (..) - это событие, прослушиватель которого добавляет в вышеупомянутый буфер и обрабатывает извлечение полной строки.

Примечание. Как уже упоминалось, это будет работать только в том случае, если изменения всегда являются дополнениями к файлу. Любые удаления вызовут проблемы.

Надеюсь, это поможет.

   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 );
                        }
                    }
                }
            }
        }
2 голосов
/ 18 сентября 2008

Я думаю, что вы должны использовать NTFS Change Journal или аналогичный:

Журнал изменений используется NTFS для обеспечить постоянный журнал всех изменения, внесенные в файлы на томе. Для каждого тома NTFS использует изменение журнал для отслеживать информацию о добавленные, удаленные и измененные файлы . Журнал изменений гораздо больше эффективнее, чем отметки времени или файл уведомления для определения изменений в данном пространстве имен.

Описание можно найти на TechNet . Вам нужно будет использовать PInvoke в .NET.

2 голосов
/ 17 сентября 2008

Правильно, FileSystemWatcher ничего не знает о содержимом вашего файла. Он скажет вам, если он изменился и т. Д., Но не то, что изменилось.

Вы только добавляете в файл? Из поста было немного неясно, были ли добавлены строки или их также можно удалить. Предполагая, что они добавлены, решение довольно простое, в противном случае вы будете делать некоторые сравнения.

1 голос
/ 17 сентября 2008

Я бы сохранил текущий текст в памяти, если он достаточно мал, а затем использовал бы алгоритм сравнения, чтобы проверить, изменился ли новый текст и предыдущий текст. Эта библиотека http://www.mathertel.de/Diff/, не только скажет вам, что что-то изменилось, но и что изменилось. Таким образом, вы можете вставить измененные данные в БД.

0 голосов
/ 17 сентября 2008

Вы правы насчет FileSystemWatcher. Вы можете прослушивать созданные, измененные, удаленные и т. Д. События, но вы не углубляетесь в файл, который их вызвал.

У вас есть контроль над самим файлом? Вы можете немного изменить модель, чтобы использовать файл как буфер. Вместо одного файла есть два. Один - это этап, один - сумма всей обработанной продукции. Прочитайте все строки из вашего «буферного» файла, обработайте их, затем вставьте их в конец другого файла, который является суммой всех обработанных строк. Затем удалите строки, которые вы обработали. Таким образом, вся информация в вашем файле ожидает обработки. Уловка в том, что если система отличается от записи (то есть также удаляет строки), она не будет работать.

0 голосов
/ 17 сентября 2008

от макушки головы, вы можете хранить последний известный размер файла. Проверьте размер файла и, когда он изменится, откройте программу чтения.

Затем найдите читателя до вашего последнего размера файла и начните чтение оттуда.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...