Чтение изменений в файле в реальном времени с помощью .NET

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

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
6 379
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

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

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

Тот факт, что размер файла не изменился, не означает, что ничего не изменилось. Гораздо более подходящим был бы хэш ... или, в данном случае, использование FileSystemWatcher.

mmcdole 19.10.2008 19:27

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

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

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

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

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

Ответ принят как подходящий

Я написал нечто очень похожее. Я использовал 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 );
                        }
                    }
                }
            }
        }

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

The change journal is used by NTFS to provide a persistent log of all changes made to files on the volume. For each volume, NTFS uses the change journal to track information about added, deleted, and modified files. The change journal is much more efficient than time stamps or file notifications for determining changes in a given namespace.

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

Другие вопросы по теме