1. Pascal / Говнокод #4887

    +102

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    function FileIsBusy(AFileName: string): Boolean;
    var
      F: Integer;
    begin
      F := FileOpen(AFileName, fmShareExclusive);
      Result := F = -1;
      FileClose(F);
    end;
    
    function WaitFile(AFileName: string; ASpeepDelay: integer): Boolean;
    begin
      while FileIsBusy(AFileName) do
        Sleep(ASpeepDelay);
      Result := True;
    end;

    пока юзверь ковыряется в Ворде, другой процесс мечтает овладеть файлом
    "It is necessary to wait of end of editing Microsoft Office files.I use next conventional approach: file is editing While file is busy" (ингриш - питерского разлива)

    это stackoverflow такими сниппетами переполнено

    Запостил: bugmenot, 10 Декабря 2010

    Комментарии (24) RSS

    • while FileIsBusy(AFileName) do
          Sleep(ASpeepDelay);

      на десктопе? ояебу
      Ответить
      • при работе от батарей такая дрочка файловой системы еще круче =)
        Ответить
        • разве это не кешируется средствами ОС?
          Ответить
          • stat наверняка кэшируется, а вот насчет того что вернуть на брутальный CreateFile - не знаю
            Ответить
          • скорее уж средствами ФС)
            Ответить
            • так прямо на диск и писать что файл открыт?
              Ответить
    • скорее не говнокод, а говноподход. По моему для ожидания лучше взять другие показатели, дату последнего редактирования, к примеру.
      Ответить
      • А чем поможет дата последнего редактирования?
        Ответить
        • ну какбы, чуть менее ебланская "проверка" будет
          Ответить
          • Если изменится last modified, то это ещё не значит, что файл освободился.
            Ответить
            • в общем случае не представляю как отследить "конец редактирования", например, для веб-аппликаций.

              а раз тут дельфи, значит, скорей всего, для редактирования он порождал новый процесс. Так что тут надо всего лишь дождаться завершения этого процесса
              Ответить
              • для уэб - возможно, но уэб-аппликации не могут ждать в сторонке покуривая
                Ответить
            • вообще да, mtime может прыгнуть до закрытия, значит говно чуть более, чем оригинал
              Ответить
    • http://msdn.microsoft.com/en-us/library/aa365465(VS.85).aspx
      Ответить
      • Тем не менее, такая функция все равно потребует дополнительной проверки на закрытость, которая и реализована в этом коде.
        Ответить
        • В этом коде реализована функция "заебу одним аккордом".

          По-нормальному, это делается открытием файла на эксклюзивный доступ однажды - после получения события об изменении файла (точнее, после таймаута событий, потому что они могут идти тоннами, например от ворда) и забыванием про него в случае INVALID_HANDLE до следующего события.
          Ответить
          • Однако не close заставляет файл измениться, а write. А между write и собственно закрытием может многое произойти. Даже если write был спровоцирован close (опустошение буферов).
            Ответить
            • Именно для этого и существует небольшой таймаут.
              Ответить
              • А почему небольшой? Может быть, большой? Кто знает, может быть после write программа будет долго что-то думать, подчищать собственные ресурсы, или ещё что, и только потом закрывать файл.
                А если программа открывала файл, но так ничего и не изменила?
                Я считаю, что в общем случае на винде задача решается только так, так написал автор якобы говнокода.
                Ответить
                • У нас уже почти два года работает приложение, построенное по схеме таймаута после события. Ни одной жалобы на то, что файл от какой-то программы не обработался, не было.
                  Ответить
                  • Это лишь означает, что в данном случае это подходит. Подходит – прекрасно, и ничего плохого в этом нет.
                    Повторюсь, что в общем случае это не будет работать.
                    Ответить
                    • Ни одна программа, кроме академической, не решает проблему в общем случае. Она решает конкретную проблему.

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

                      1. Открыл файл, записал, закрыл
                      2. Создал новый файл, записал в него, переименовал старый в темп, переименовал новый в старый

                      Алгоритм, который я описываю, покрывает оба этих случая.
                      Ответить
                    • Впрочем, как выяснилось опытным путем, оно работает потому, что работает.

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

                      [STAThread]
                      static void Main(string[] args)
                      {
                      FileSystemWatcher fsw = new FileSystemWatcher();
                      fsw.Path = "D:\\";
                      fsw.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.Size | NotifyFilters.FileName;
                      fsw.EnableRaisingEvents = true;
                      fsw.Filter = "*";

                      fsw.Changed += new FileSystemEventHandler(fsw_Changed);

                      Stream s = new FileStream("D:\\test1.txt", FileMode.Create, FileAccess.Write);
                      s.Write(new byte[500], 0, 500);
                      s.Flush();
                      Thread.Sleep(10000);
                      s.Close();
                      Console.ReadLine();
                      }

                      static void fsw_Changed(object sender, FileSystemEventArgs e)
                      {
                      Console.WriteLine("{0}: {1}", e.ChangeType, e.Name);
                      }

                      Выводит 2 события Changed. Первое при изменении, второе при закрытии.
                      Ответить
                      • Забавно - закрытие не бампает mtime, но тем не менее вызывает событие. Что ж, тогда вы были правы.
                        P.S. Жаль, что на MSDN не документированы все тонкости.
                        Ответить

    Добавить комментарий