Замена содержимого файла без читателей прерывания доступа клиентов - PullRequest
1 голос
/ 21 мая 2011

Существует служба, которая постоянно записывает новый контент в файл:

using (var stream = File.Create(FileName))     // overwrites the file
{
    stream.Write(data, 0, data.Length);
}

Файл постоянно доступен нескольким читателям (включая веб-приложение, которое отображает его содержимое из этого файла). Я не контролирую читателей кода клиента. Файл всегда должен быть доступен для читателей. Более того, они должны видеть весь контент, а не контент в середине записи в файл.

Любые техники, подобные этой:

using (var stream = File.Create(FileName + ".tmp"))
{
    stream.Write(data, 0, data.Length);
}

File.Delete(FileName);
File.Move(FileName + ".tmp", FileName);

может привести к отсутствию контента на веб-странице (с некоторой вероятностью). А служба иногда выдает исключение IOException с сообщением «Процесс не может получить доступ к файлу, поскольку он используется другим процессом».

Вопрос в следующем: Как можно постоянно заменять содержимое файла без прерывания доступа клиентов для чтения?

1 Ответ

0 голосов
/ 24 мая 2011

В IIS вы можете адаптировать этот модуль (полное раскрытие я написал) для внедрения синхронизации в запросы на чтение. Вы могли бы сделать это, создав подкласс InterceptingHandler и добавив такой код:

SychronizingHandler : InterceptingHandler
{
    // ...

    Semaphore mySemaphore;

    protected override bool PreFilter(System.Web.HttpContext context)
    {
        context.RewritePath("myFilePath");
        if( mySemaphore == null)
        {
            bool created;
            mySemaphore = new Semaphore(100, 0, "semphoreName", out created);
        }

        if( mySemaphore != null)
        {
            mySemaphore.WaitOne();
        }
        reutrn true;
    }

    // note this function isn't in the base class
    // you would need to add it  and call it right after the call to
    // innerHandler.ProcessRequest
    protected override void PostFilter(System.Web.HttpContext context) 
    {
        mySemaphore.Release();
        return;
    }

    protected virtual void OnError(HttpContext context, Exception except)
    {
        mySemaphore.Release();
        return base.OnError(context, except);
    }

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

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

...