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

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

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

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

Сообщение voltron » 03.11.2008 17:40:50

Есть у нас в конторе программа (написанная не мной), которая читает текстовые файлы определенного формата, извлекает из них информацию, и после форматирования пишет ее в результирующий файл. Вот фрагмент кода:
Код: Выделить всё
// просматриваем исходные файлы
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). Файл-результат больше нигде не используется, после записи каждой порции данных закрывается. Пробовал вынести открытие и закрытие результирующего файла за пределы цикла (чтобы не открывать файл при записи новой порции данных) - не помогло.
В чем может быть проблема и как лучше организовать процесс записи (пишутся строки разной длины)?
voltron
новенький
 
Сообщения: 64
Зарегистрирован: 06.07.2007 13:27:46
Откуда: Украина

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

Сообщение FedeX » 03.11.2008 17:49:16

Попробуй использовать функцию Flush перед записью следующей порции. (я ей не пользовался, но вроде есть такая).
Попробуй писать всё в одну строку (конкатенировать или, если возможно, сразу выделить необходимый обьём), и только в конце писать всю строку в бинарный файл.
Аватара пользователя
FedeX
постоялец
 
Сообщения: 422
Зарегистрирован: 27.03.2006 09:25:34
Откуда: украина, житомир

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

Сообщение Vadim » 03.11.2008 18:14:13

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;

Съэкономит кучу времени, т.к. выходной файл открывается всего один раз.
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

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

Сообщение voltron » 03.11.2008 18:44:26

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

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

Именно так и собираюсь поступить. Просто интересует причина появления таких ошибок. Нашел на Королевстве Дельфи похожую проблему http://www.delphikingdom.com/asp/answer.asp?IDAnswer=50614
voltron
новенький
 
Сообщения: 64
Зарегистрирован: 06.07.2007 13:27:46
Откуда: Украина

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

Сообщение Vadim » 03.11.2008 19:18:26

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

Точно сказать не могу, т.к. ни разу с таким не сталкивался, но, возможно, причина в кэшировании. Файл при следующей итерации, пытается открываться раньше, чем успевает сбросить туда данные предыдущая итерация. Отсюда и "Access denied". Впрочем, может быть и ошибаюсь. :) А вообще предпочитаю не проводить множественные открытия-закрытия файлов, т.к. это сильно тормозит программу.
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

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

Сообщение Logo » 03.11.2008 21:09:32

Здесь видимо превышает допустимое количество открытых файлов. Тоесть, в цикле идет быстрая посылка комманд (сообщений) системе, система файлы откравыет, но закрывает с запаздыванием. Если нельзя изменить алгоритм, то побробуйте вставить Application.ProcessMessage после закрытия файла, да и после открытия можно (будет еще тормознутее :) ).
Logo
постоялец
 
Сообщения: 464
Зарегистрирован: 20.08.2008 01:00:47

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

Сообщение shade » 03.11.2008 21:18:11

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

Если результат больше нигде не используется, то может и не закрывать? Один раз открыл и пиши?...
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

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

Сообщение Padre_Mortius » 04.11.2008 01:45:50

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

Код: Выделить всё
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;
Padre_Mortius
энтузиаст
 
Сообщения: 1265
Зарегистрирован: 29.05.2007 17:38:07
Откуда: Спб


Вернуться в Общее

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 11

Рейтинг@Mail.ru