Delphi7 - Как я могу скопировать файл, который записывается в - PullRequest
3 голосов
/ 14 января 2011

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

Размер этих файлов не должен превышать 30-40 МБ каждый. сеть будет 100 МБ Ethernet. Я вижу, что процесс копирования может занять больше 1 секунды, что означает, что ПК, на котором ведется запись, потребуется открыть файл для записи во время его чтения.

Каков наилучший метод для процедуры записи (регистрации) и копирования файлов? Я знаю, что есть стандартная процедура Windows CopyFile (), однако это вызвало проблемы с доступом к файлам. Существует также TFileStream, использующий флаг fmShareDenyNone, но это также очень редко вызывает проблемы с доступом (например, 1 в неделю).

Что это лучший способ выполнить эту задачу?

Моя текущая регистрация файлов:

procedure FSWriteline(Filename,Header,s : String);
var LogFile : TFileStream;
line : String;
begin
     if not FileExists(filename) then
     begin
          LogFile := TFileStream.Create(FileName, fmCreate or fmShareDenyNone);
          try
             LogFile.Seek(0,soFromEnd);
             line := Header + #13#10;
             LogFile.Write(line[1],Length(line));
             line := s + #13#10;
             LogFile.Write(line[1],Length(line));
          finally
                 logfile.Free;
          end;
     end else begin
         line := s + #13#10;
         Logfile:=tfilestream.Create(Filename,fmOpenWrite or fmShareDenyNone);
         try
            logfile.Seek(0,soFromEnd);
            Logfile.Write(line[1], length(line));
         finally
            Logfile.free;
         end;
     end;
end;

Процедура копирования моего файла:

procedure DoCopy(infile, Outfile : String);
begin
     ForceDirectories(ExtractFilePath(outfile)); //ensure folder exists
     if FileAge(inFile) = FileAge(OutFile) then Exit; //they are the same modified time
     try
        { Open existing destination }
        fo := TFileStream.Create(Outfile, fmOpenReadWrite or fmShareDenyNone);
        fo.Position := 0;
     except
           { otherwise Create destination }
           fo := TFileStream.Create(OutFile, fmCreate or fmShareDenyNone);
     end;
     try
        { open source }
        fi := TFileStream.Create(InFile, fmOpenRead or fmShareDenyNone);
        try
           cnt:= 0;
           fi.Position := cnt;
           max := fi.Size;
           {start copying }
           Repeat
                 dod := BLOCKSIZE; // Block size
                 if cnt+dod>max then dod := max-cnt;
                 if dod>0 then did := fo.CopyFrom(fi, dod);
                 cnt:=cnt+did;
                 Percent := Round(Cnt/Max*100);
           until (dod=0)
        finally
               fi.free;
        end;
     finally
            fo.free;
     end;
end;

Ответы [ 4 ]

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

Я бы посоветовал не закрывать и снова открывать общий файл снова и снова.Поскольку вы пишете в него каждую секунду, это просто ненужные накладные расходы.

На стороне мастера создайте и закройте файл (флаг fmCreate нельзя использовать с другими флагами!), А затем снова откройте егов режиме fmOpenWrite с общим доступом fmShareDenyWrite оставьте его открытым и, при необходимости, напишите в него.

На ведомой стороне откройте файл в режиме fmOpenRead с общим доступом fmShareDenyNone, оставьте его открытыми читайте из него каждую секунду.Нет необходимости каждый раз копировать весь общий файл по сети.Это потраченная впустую пропускная способность.Просто прочитайте все новые данные, которые были записаны за последние несколько секунд, и это все.Если ведомому требуется, чтобы данные были сохранены в локальном файле, он может управлять отдельным локальным файлом независимо от общего файла, вставляя новые данные в локальный файл, когда это необходимо.

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

Для решения вашей конкретной периодически повторяющейся проблемы:

Вы не говорите, какую версию Delphi вы используете.

В конструкторе TFileStream.Create () возникла ошибка.до версии 2007 года включительно (как минимум).Это может объяснить ваши случайные проблемы с параллелизмом.

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

Один из способов обойти это может быть, когда файл должен быть создан, сначала создайте файл, а затем просто откройте его для записи как отдельный вызов конструктора - это фактически делает создание файла отдельным шагом,с записью в файл последовательной части процесса:

  if not FileExists(filename) then
  begin
    // There may be a more efficient way of creating an empty file, but this 
    //  illustrates the approach

    LogFile := TFileStream.Create(FileName, fmCreate);
    LogFile.Free;

    line := Header + #13#10 + s + #13#10;
  end
  else
    line := s + #13#10;

  Logfile:=tfilestream.Create(Filename,fmOpenWrite or fmShareDenyNone);
  try
    logfile.Seek(0,soFromEnd);
    Logfile.Write(line[1], length(line));
  finally
    Logfile.free;
  end;
0 голосов
/ 14 января 2011

поиск функции с именем "IsFileInUse" или чего-то подобного, я уверен, что вы можете использовать это как:

// master
while IsFileInUse(*AFileName*) do
  Sleep(10);
write-content-to-file

// slave
while IsFileInUse(*AFileName*) do
  Sleep(10);
copy-file-to-a-special-location

и presto !!все готово !!

0 голосов
/ 14 января 2011

Используйте стандартную Добавить команду создания / открытия файла, используйте write для обновления журнала и close файл немедленно.

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

Если вы хотите сделать это из Delphi, используйте MoveFile , чтобы переместить все это.

Возможно, вы захотите обернуть как записи журнала, так и ходы в try-except, чтобы их можно было повторить разумное количество раз, если файловая система (NTFS в Windows?) Не разрешает параллелизм за вас. В худшем случае либо:

  1. Файл перемещен, и он воссоздан и записан.
  2. Файл не перемещается сразу, потому что он записывается в.

Если ОС не разрешает условие гонки, вам нужно будет отдать приоритет голодному действию, используя семафор / блокировку.

...