Читая файл сразу после его записи, я получаю все нули (.net) - PullRequest
3 голосов
/ 20 января 2011

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

Чтобы не пытаться прочитать файл, который все еще пишется, у меня есть такой код:

try {
    fs = fi.Open(FileMode.Open, FileAccess.ReadWrite,
                    FileShare.None);
    message = new byte[fs.Length];
    int br = fs.Read(message, 0, (int)fi.Length);
}
catch (Exception e) {
    // I'll get it next time around
    return;
}
finally {
    if (fs != null)
        fs.Close();
}

Проблема в том, что для некоторых файлов, примерно 1 к 200, программа считывает все нули. Длина файла правильная, но содержимое кажется равным нулю байтов. Когда я проверяю последний файл, я обнаруживаю, что он действительно содержит правильные данные. Я думал, что способ открытия файла предотвратит преждевременный доступ к файлу.

Я проверяю это, копируя файлы в каталог с помощью команды DOS 'copy InFile_0 * dropdir' (около 100 файлов за выполнение.) Возможно, эта команда выполняет копирование в два этапа: 1) выделить пространство и 2) заполнить пробел и моя программа иногда прыгает в середине двух.

Любые идеи о том, как кодировать это, чтобы быть надежным?

Обновление: У меня нет контроля над программой записи - это может быть что угодно. Похоже, я должен защищаться.

Ответы [ 2 ]

2 голосов
/ 20 января 2011

Вы попали в состояние гонки. От этого будет только хуже (с сетевыми файловыми системами и т. Д.), Если вы не исправите это окончательно.

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

Или сохраните файл нулевой длины с именем «sentinel» или что-то подобное в каталоге. Получите программу, записывающую файлы для перезаписи сторожевого файла ПОСЛЕ каждой успешной записи другого файла. Затем не пытайтесь читать файлы, у которых дата / время изменения> = дата / время изменения сторожевого файла.

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

Удачи. Это пресловутая боль в шее.

1 голос
/ 20 января 2011

Ну, я не согласен с предыдущим постом @Ollie Jones.

Вы уже установили монопольный доступ к файлу, поэтому проблем с условиями гонки нет.

Я думаю, вам следует изучить поведение писателя более тщательно. И попробуйте уменьшить помехи при доступе к файлу только для чтения, поделитесь всем доступом:

fi.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

Это может привести к ошибке чтения, но уменьшит ошибку записи. Чтобы решить, когда читать безопасно, вы можете проверить время файла или размер файла или что-то еще. Если впоследствии будет записано много файлов, вы можете начать чтение первого файла после создания второго.

...