Access denied при частом открытии файла

Общие вопросы программирования, алгоритмы и т.п.

Модератор: Модераторы

Ответить
voltron
новенький
Сообщения: 64
Зарегистрирован: 06.07.2007 13:27:46
Откуда: Украина

Access denied при частом открытии файла

Сообщение voltron »

Есть у нас в конторе программа (написанная не мной), которая читает текстовые файлы определенного формата, извлекает из них информацию, и после форматирования пишет ее в результирующий файл. Вот фрагмент кода:

Код: Выделить всё

// просматриваем исходные файлы
for i:=0 to lstFiles.Lines.Count - 1 do
begin
  //сначала считывается и обрабатывается исх. файл
  lstSource.LoadFromFile(lstFiles.Lines[i]);
  ...

  //результат обработки пишем в результирующий файл
  AssignFile(OutFile, OutFileName);
  try
    Append(OutFile);
   
    //запись информации
    write(OutFile, CadNom + SEPARATOR);
    write(OutFile, Owner + SEPARATOR);
    ...
    writeln(OutFile, ActRegDate); //формируем переход на след. строку
    CloseFile(OutFile);
  except
    on E:EInOutError do
      DebugLn('Error: ' + E.Message);
  end;
end;

При большом количестве исходных файлов (4000 и больше), ближе к концу списка начинает возникать ошибка "Access denied" на строке Append(OutFile). Файл-результат больше нигде не используется, после записи каждой порции данных закрывается. Пробовал вынести открытие и закрытие результирующего файла за пределы цикла (чтобы не открывать файл при записи новой порции данных) - не помогло.
В чем может быть проблема и как лучше организовать процесс записи (пишутся строки разной длины)?
Аватара пользователя
FedeX
постоялец
Сообщения: 422
Зарегистрирован: 27.03.2006 09:25:34
Откуда: украина, житомир

Сообщение FedeX »

Попробуй использовать функцию Flush перед записью следующей порции. (я ей не пользовался, но вроде есть такая).
Попробуй писать всё в одну строку (конкатенировать или, если возможно, сразу выделить необходимый обьём), и только в конце писать всю строку в бинарный файл.
Vadim
долгожитель
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Сообщение Vadim »

voltron
Попробуйте вообще использовать класс TStringList. У него есть метод SaveToFile(), при этом он сразу выкидывает в файл весь свой набор строк:

Код: Выделить всё

Var
  st: TStringList;
Begin
st:=TStringList.Create;
// просматриваем исходные файлы
for i:=0 to lstFiles.Lines.Count - 1 do
begin
  //сначала считывается и обрабатывается исх. файл
  lstSource.LoadFromFile(lstFiles.Lines[i]);
  ...

  //результат обработки пишем в StringList
   
    //запись информации
    st.Add(CadNom + SEPARATOR + Owner + SEPARATOR+...);
    ...
End;
st.SaveToFile(OutFileName);
st.Free;

Съэкономит кучу времени, т.к. выходной файл открывается всего один раз.
voltron
новенький
Сообщения: 64
Зарегистрирован: 06.07.2007 13:27:46
Откуда: Украина

Сообщение voltron »

FedeX писал(а):Попробуй использовать функцию Flush перед записью следующей порции. (я ей не пользовался, но вроде есть такая).

Есть такая процедура, она выполняет принудительную запись изменений (сбрасывает файловый буфер на диск). Данные нормально пишутся и без нее, проблема возникает при попытке открыть файл на дозапись, т.е. Flush здесь не причем.
Vadim писал(а):Попробуйте вообще использовать класс TStringList

Именно так и собираюсь поступить. Просто интересует причина появления таких ошибок. Нашел на Королевстве Дельфи похожую проблему http://www.delphikingdom.com/asp/answer.asp?IDAnswer=50614
Vadim
долгожитель
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Сообщение Vadim »

voltron писал(а):Просто интересует причина появления таких ошибок.

Точно сказать не могу, т.к. ни разу с таким не сталкивался, но, возможно, причина в кэшировании. Файл при следующей итерации, пытается открываться раньше, чем успевает сбросить туда данные предыдущая итерация. Отсюда и "Access denied". Впрочем, может быть и ошибаюсь. :) А вообще предпочитаю не проводить множественные открытия-закрытия файлов, т.к. это сильно тормозит программу.
Logo
постоялец
Сообщения: 464
Зарегистрирован: 20.08.2008 01:00:47

Сообщение Logo »

Здесь видимо превышает допустимое количество открытых файлов. Тоесть, в цикле идет быстрая посылка комманд (сообщений) системе, система файлы откравыет, но закрывает с запаздыванием. Если нельзя изменить алгоритм, то побробуйте вставить Application.ProcessMessage после закрытия файла, да и после открытия можно (будет еще тормознутее :) ).
Аватара пользователя
shade
энтузиаст
Сообщения: 879
Зарегистрирован: 21.02.2006 19:15:48
Откуда: http://shamangrad.net/
Контактная информация:

Сообщение shade »

voltron писал(а):Файл-результат больше нигде не используется, после записи каждой порции данных закрывается.

Если результат больше нигде не используется, то может и не закрывать? Один раз открыл и пиши?...
Padre_Mortius
энтузиаст
Сообщения: 1265
Зарегистрирован: 29.05.2007 17:38:07
Откуда: Спб

Сообщение Padre_Mortius »

тоже столкнулся с этой проблемой. Только работу с файлом оформил через потоки. Ошибка плавающая. Повторить ее получается крайне редко (у меня).

Код: Выделить всё

Procedure WriteToLog(Const FileStr, PathStr, Code: AnsiString);
Var
  LogStream: TFileStream;
  ResultStr, S, LogFileName: AnsiString;
Begin
  LogFileName := ExtractFilePath(ParamStr(0)) + 'Log\transport.log';
  ResultStr := Code;
  S := '';
  Try
    If Not FileExists(LogFileName) Then
      LogStream := TFileStream.Create(LogFileName, fmCreate)
    Else LogStream := TFileStream.Create(LogFileName, fmOpenWrite);
    LogStream.Seek(0, sofromEnd);
    If length(FileStr)<>0 Then ResultStr := StringReplace (Code, '%f', FileStr, [rfReplaceAll]);
    If length(PathStr)<>0 Then ResultStr := StringReplace (ResultStr, '%s', PathStr, [rfReplaceAll]);
    DateTimeToString(S, 'DD.MM.YYYY HH:NN:SS ', Now);
    ResultStr := S + ' ' + ResultStr + #13 + #10;
    LogStream.Write (PChar(ResultStr)[0], Length(ResultStr));
  Finally
    LogStream.Free;
  End;
End;
Ответить