Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Поиск последнего созданного файла в каталоге


Автор: ivanfr 15.3.2012, 09:47
Суть такая есть, каталог, в который производится выгрузка xls файлов с данными, эти файлы  я через свою программку обрабатываю.
Количество файлов растёт, а постоянно через вызов "диалога" не натыкаешься ручками, надоело на это тратить время к тому же таких каталогов штук шесть. Захотелось автоматизировать и этот процесс.
Короче суть такая:
К работе на текущий день нужен актуальный файл, который выгрузился, вчера ночью, а сегодня утром нужно его обработать. Открываю программку, ищу файл,  выбираю и жму обработать.
Думаю, дайка напишу, что бы программа сама находила самый последний по дате выгруженный файл и брала его к обработке.
Тут столкнулся с проблемой, как бы это реализовать?!
Почитала, что люди пишу.  И решил делать так.
Есть у меня ранее подогнанный  код под мои нужды, который ищет в заданном каталоге xls файлы и берет их к обработке.
На сайте нашёл кусок кода, который находит файл с устаревшим времем от системного времени на 5 минут и выводит сообщение не много не то что я хотел.
Данный код мне ничего не даёт.
Код

begin
  try
    while FindFirst('c:\*.*', faAnyFile, SearchRec) = 0 do
         begin
            MyFileTime := SearchRec.FindData.ftCreationTime;
            Application.ProcessMessages;
            FileTimeToSystemTime(MyFileTime,MyFileSysTime);
              GetSystemTime(MySysTime);
            MyFileDate := SystemTimeToDateTime(MyFileSysTime);
            Application.ProcessMessages;
            MySysDate := SystemTimeToDateTime(MySysTime);
            Delta := MySysDate - MyFileDate;
            if Delta / MyMin > 5 Then ShowMessage('Файл устарел');
         end;
  finally
    FindClose(SearchRec);
  end;


А вот если я возьму, получу  текущую системную дату, сравню с первым найденным файлом в каталоге и посмотрю разницу, затем  цикл while найдет второй файл, получу интервал между системой датой и  датой второго найденного файла  и сравню с первым полученным результатом(интервалом), и так далее  пока не получу самый маленький интервал между системной датой и датой создания файла, который и буду считать последним созданным файлом в каталоге.
Вопрос  будет ли это правильно или можно лучше сделать, а может, есть функции, которые умеют искать последний созданный файл в каталоге.
А может сделать так: записать все обработанные  на данный момент файлы в каталоге в текстовый файл, при  обработке нового файла искать с помощью «pos» в  текстовом файле совпадения, если найден в файле, значит файл обработан, если нет, то обработать?


Автор: Akella 15.3.2012, 09:52
Цитата(ivanfr @  15.3.2012,  09:47 Найти цитируемый пост)
‘c:\*.*'

ничего не замечаешь?

Автор: ivanfr 15.3.2012, 11:04
Ну это понятно что там ошибка.
Я вопросы то другие задавал.

Автор: Snowy 15.3.2012, 13:03
Код
var
  sr: TSearchRec;
  fn: string;
  st: TSystemTime;
  dt,ft: TDateTime;
begin
  fn := '';
  dt := 0;
  try
    if FindFirst('C:\*.*', faAnyFile, sr) = 0 then
    repeat
      if sr.Attr = faDirectory then Continue;      
      FileTimeToSystemTime(sr.FindData.ftCreationTime, st);
      ft := SystemTimeToDateTime(st);
      if ft > dt then
      begin
        dt := ft;
        fn := sr.Name;
      end;
    until (FindNext(sr) <> 0);
  finally
    FindClose(sr);
  end;
  if fn = '' then ShowMessage('Нет Файлов')
  else ShowMessage('Самый новый файл: ' + fn);
end;

Автор: ivanfr 16.3.2012, 11:22
Так как у меня в данную папку выгружается по 4 отчета, но названия разные, а мне нужен только под определенным именем. А код приведенный выше выводит только последний созданный файл в каталоги  и он не подходит, привел небольшую модификацию.  Добавил на проверку наличия в переменной имени файла определенного значения. 
Посоветуйте, корректно ли так использовать код или могут быть проблемы?

Код

var
  SR: TSearchRec;
  fn: string;
  st: TSystemTime;
  dt,ft: TDateTime;
  index:integer;
  Directory_Path, Data:string;
 begin
  fn := '';
  dt := 0;
  try
    if FindFirst('C:\*.xls', faAnyFile, SR) = 0 then
    repeat
       index:=AnsiPos('тут кусок имени файла',SR.Name);
       if index = 0 then Continue
       else
        begin
          if SR.Attr = faDirectory then Continue;
          FileTimeToSystemTime(SR.FindData.ftCreationTime, st);
          ft := SystemTimeToDateTime(st);
          if ft > dt then
          begin
            dt := ft;
            fn := SR.Name;
          end;
        end;
    until (FindNext(SR) <> 0);
  finally
    FindClose(SR);
  end;
  if fn = '' then Continue//ShowMessage('Нет Файлов')
  else
    begin
      Directory_Path:= ExpandFileName(SR.Name);
      Form2.Label3.Caption:=Directory_Path;
      ShowMessage('Самый новый файл: ' + fn);
    end;
end;

 

Автор: ivanfr 16.3.2012, 12:38
Помогите решить проблему?
Нужно пять раз прогнать выше приведенный код загоняю его в цикл for.

с кодом почему-то при использовании цикла в переменную присваивает 5, в место 0 ни чего не понимаю.


Код

 for i:=0 to 4 do 
begin
end;



Автор: Snowy 16.3.2012, 12:44
В переменную присваивается поочереди - 0, 1, 2, 3, 4, 5
По окончании цикла в ней останется 5.
Всё логично.

Автор: ivanfr 16.3.2012, 12:58
  ну вот кусок кода когда подходи к dr у него в значении 5 хотя я его перед циклом обнуляю? 
Код


DirectoryList[0]:='каталог 1';
  DirectoryList[1]:='каталог 2';
  DirectoryList[2]:='каталог 3';
  DirectoryList[3]:='каталог 4';
  DirectoryList[4]:='каталог5 ';
  fn := '';
  dt := 0;
 [quote]
 dr := 0;
[/quote]
  for dr:= 0 to 4 do
  begin
   try
      if FindFirst(DirectoryList[dr], faAnyFile, SR) = 0 then
        repeat
          index:=AnsiPos('имя нужного файла',SR.Name);
          if index = 0 then Continue
            else
              begin
                if SR.Attr = faDirectory then Continue;
                FileTimeToSystemTime(SR.FindData.ftCreationTime, st);
                ft := SystemTimeToDateTime(st);
                if ft > dt then
                  begin
                    dt := ft;
                    fn := SR.Name;
                  end;
              end;
        until (FindNext(SR) <> 0);
    finally
      FindClose(SR);
    end;
    if fn = '' then Continue//ShowMessage('Нет Файлов')
    else
      begin
        DirectoryPath:= ExpandFileName(SR.Name);
        Form2.Label3.Caption:=DirectoryPath;
        ShowMessage('Самый новый файл: ' + fn);
      end;
end;
end;



 и вообще почему он пропускает строку  dr := 0;

Автор: Snowy 16.3.2012, 13:14
Нет, в этом куске кода dr не может принимать значения 5. Никак.

Автор: ivanfr 16.3.2012, 13:26
Но почему-то принимает? 

http://s2.ipicture.ru/

Автор: Keeper89 16.3.2012, 19:32
Сдается мне, что отладка идет по какому-то другому модулю.

Автор: ivanfr 17.3.2012, 09:55
Мне ранее уже встречалась такая проблема. Когда писал дипломную работу, тоже косяк был вместо нулевого значения подставлялось другое на первом проходе цикла. Что делал не помню.

Вот почему, перед for пропускается присвоение переменной, странно как-то? Посидел, подумал сегодня и у меня есть подозрение, что это косяк происходит из-за  конструкции try except end. Нужно попробовать в понедельник перенести  try перед for i=.. 

Автор: Akella 17.3.2012, 11:16
Попробуй отключи оптимизацию в свойствах проекта

Автор: ivanfr 19.3.2012, 07:52
Отключение оптимизации в свойствах проекта помогло, только не сразу, а через пару запусков.
Обнуление переменной dr - пропускать перестал. 

Автор: Akella 19.3.2012, 10:36
После изменения настроек проекта, нужно выполнить перекомпиляцию.
Но для готовой программы лучше включать оптимизицию.

Автор: ivanfr 5.7.2012, 14:42
Народ!

Помогите изменить код. сейчас в каталог выгружается каждый день - 5 файлов с одинаковой датой, но с разным временем создания (файл1 :11.06.2012, 11.00, 59, 123 файл2 :11.06.2012, 11.01, 35, 451.....). эти пять файлов отличаются на секунды.

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

Возникла идея добавить 
Код
if FindFirst(DirectoryList[dr], faAnyFile, SR) = 0 and obraotfile  = SR.Name  then  
 доп исключение, но не получилось. 



Код


  DirectoryList[0]:='каталог 1';
  DirectoryList[1]:='каталог 2';
  DirectoryList[2]:='каталог 3';
  DirectoryList[3]:='каталог 4';
  DirectoryList[4]:='каталог5 ';
  fn := '';
  dt := 0;
 [quote]
 dr := 0;
[/quote]
  for dr:= 0 to 4 do
  begin
   try
      if FindFirst(DirectoryList[dr], faAnyFile, SR) = 0 then 
        repeat
          index:=AnsiPos('имя нужного файла',SR.Name);
          if index = 0 then Continue
            else
              begin
                if SR.Attr = faDirectory then Continue;
                FileTimeToSystemTime(SR.FindData.ftCreationTime, st);
                ft := SystemTimeToDateTime(st);
                if ft > dt then
                  begin
                    dt := ft;
                    fn := SR.Name;
                  end;
              end;
        until (FindNext(SR) <> 0);
    finally
      FindClose(SR);
    end;
    if fn = '' then Continue//ShowMessage('Нет Файлов')
    else
      begin
        DirectoryPath:= ExpandFileName(SR.Name);
        Form2.Label3.Caption:=DirectoryPath;
        ShowMessage('Самый новый файл: ' + fn);
      end;
end;
end;


  

Автор: ivanfr 9.7.2012, 14:14
Прошу, глянуть код на наличие ошибок. В таком виде работает как мне нужно. Может кто подскажет, как оптимизировать или заменить? 
Решил свою пробему так:

Код


//Так вызываю
procedure TForm2.BitBtn6Click(Sender: TObject);
var
directoryList : array [0..4] of string;
directoryListData : array  [0..4] of TDateTime;

begin
 SearchFreshFile(directoryList, directoryListData);
end;

Вот сам код

Код

procedure SearchFreshFile(var directoryList:array of string; var directoryListData : array of TDateTime);
 var
  SR: TSearchRec;
  fn,ActualFileName: string;
  st: TSystemTime;
  dt,ft: TDateTime;
  dr, counter:integer;
  DirectoryPath, Data, w,TimeCreate,TimeCreate1 :string;
 label metka1;
begin
  //Обнуление переменных
  counter:=0;
  fn := '';
  dt := 0;
  dr := 0;
  directoryList[0]:='';
  directoryList[1]:='';
  directoryList[2]:='';
  directoryList[3]:='';
  directoryList[4]:='';
  directoryListData[0]:=0;
  directoryListData[1]:=0;
  directoryListData[2]:=0;
  directoryListData[3]:=0;
  directoryListData[4]:=0;
  metka1:
  if FindFirst('c:\Reports\'+'*.xls', faAnyFile, SR) = 0 then
    repeat
      w:='c:\Reports\'+sr.Name;
      if SR.Attr = faDirectory then Continue;
      FileTimeToSystemTime(SR.FindData.ftCreationTime, st);
      ft := SystemTimeToDateTime(st);
      if counter>4 then begin  ShowMessage('Переполнение массива:  directoryList и directoryListData '); exit; end;
      if directoryList[0]<>''then
        begin
          if ((FormatDateTime('dd.mm.yyyy', ft) = FormatDateTime('dd.mm.yyyy', directoryListData[0])) and ('c:\Reports\'+sr.Name <> directoryList[0]))
            then
              begin
                directoryList[counter]:='c:\Reports\'+ sr.Name;
                directoryListData[counter]:=ft;
                if counter<4 then inc(counter);//будет ошибка если больше массив расчитан на до 4
              end;
        end;
      if ft > dt then //ищет самую новую дату файла, включая время. 
        begin
          dt := ft;
          fn := SR.Name;
        end;
   until (FindNext(SR) <> 0);
    if fn = '' then
    else
      begin
        directoryList[0]:='c:\Reports\'+SR.Name;
        directoryListData[0]:=ft;
        if directoryList[4]=''then  begin inc(counter); goto metka1; end;
     end;
   FindClose(SR);
 end;


Автор: Akella 9.7.2012, 20:05
Цитата(ivanfr @  9.7.2012,  14:14 Найти цитируемый пост)
'c:\Reports\'


За такое на кол!

Автор: ivanfr 10.7.2012, 08:29
Цитата

За такое на кол!

Почему так делать не стоит? 
Лучше в переменную присваивать?

Автор: Akella 10.7.2012, 10:05
1. В корень системного диска никогда не пиши. Даст по рукам или система, или пользователи. Для своих каких-то файлов есть профиль пользователя.
2. Да, переменная или константа.
3. Может быть стоит внести пусть в настройки, чтобы пользователь сам смог, если понадобится, изменить путь по умолчанию?

Автор: ivanfr 10.7.2012, 11:16
Цитата

1. В корень системного диска никогда не пиши. Даст по рукам или система, или пользователи. Для своих каких-то файлов есть профиль пользователя

Не, у меня путь на сетевой диск - это я для примера, чтоб понятно было. 

Автор: Akella 10.7.2012, 11:25
Цитата(ivanfr @  10.7.2012,  11:16 Найти цитируемый пост)
 меня путь на сетевой диск

Тогда будь готов к зависаниям программы, особенно если винды кривые или права неправильно дадены.

Автор: ivanfr 10.7.2012, 11:37
Это да(ошибки и права), Подскажи лучше как мне сделать обработчик событий.
try exept end не дает использовать метки(goto)?

Автор: Akella 10.7.2012, 12:12
Цитата(ivanfr @  10.7.2012,  11:37 Найти цитируемый пост)
использовать метки(goto)?

и не надо, забудь про них

Автор: ivanfr 10.7.2012, 12:18
А тогда у меня не получается, получить пути.

Вот тут вот.

Код

procedure SearchFreshFile(var directoryList:array of string; var directoryListData : array of TDateTime);
 var
  SR: TSearchRec;
  fn,ActualFileName: string;
  st: TSystemTime;
  dt,ft: TDateTime;
  dr, counter:integer;
  DirectoryPath, Data, w,TimeCreate,TimeCreate1 :string;
 label metka1;
begin
  //Обнуление переменных
  counter:=0;
  fn := '';
  dt := 0;
  dr := 0;
  directoryList[0]:='';
  directoryList[1]:='';
  directoryList[2]:='';
  directoryList[3]:='';
  directoryList[4]:='';
  directoryListData[0]:=0;
  directoryListData[1]:=0;
  directoryListData[2]:=0;
  directoryListData[3]:=0;
  directoryListData[4]:=0;
  metka1:
  if FindFirst('c:\Reports\'+'*.xls', faAnyFile, SR) = 0 then
    repeat
      w:='c:\Reports\'+sr.Name;
      if SR.Attr = faDirectory then Continue;
      FileTimeToSystemTime(SR.FindData.ftCreationTime, st);
      ft := SystemTimeToDateTime(st);
      if counter>4 then begin  ShowMessage('Переполнение массива:  directoryList и directoryListData '); exit; end;
      if directoryList[0]<>''then
        begin
          if ((FormatDateTime('dd.mm.yyyy', ft) = FormatDateTime('dd.mm.yyyy', directoryListData[0])) and ('c:\Reports\'+sr.Name <> directoryList[0]))
            then
              begin
                directoryList[counter]:='c:\Reports\'+ sr.Name;
                directoryListData[counter]:=ft;
                if counter<4 then inc(counter);//будет ошибка если больше массив расчитан на до 4
              end;
        end;
      if ft > dt then //ищет самую новую дату файла, включая время. 
        begin
          dt := ft;
          fn := SR.Name;
        end;
   until (FindNext(SR) <> 0);
    if fn = '' then
    else
      begin
        directoryList[0]:='c:\Reports\'+SR.Name;
        directoryListData[0]:=ft;
        if directoryList[4]=''then  begin inc(counter); goto metka1; end;
     end;
   FindClose(SR);
 end;

Автор: Akella 10.7.2012, 12:39
Мне кажется, что тебе нужно использовать рекурсию

Добавлено через 9 минут и 7 секунд
Сделать процедуру функцией и вызывать саму себя

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)