繁体   English   中英

使用Delphi在目录中查找最早文件的最快方法

[英]Quickest way to find the oldest file in a directory using Delphi

您好

我们有大量的远程计算机将视频捕获到磁盘驱动器上。 每个摄像机都有其自己的唯一目录,并且每个磁盘上最多可以有16个目录。

我正在尝试在磁盘上找到最旧的视频文件,但是使用FindFirst/FindNext比较文件创建日期时间会花费很多时间。

有人知道在目录中查找最旧文件的更有效方法吗? 我们从中央HO位置远程连接到PC。

问候,彼得

-更新

谢谢大家的回答。 最后,我使用了以下内容。

  1. 使用windows.WNetAddConnection2将驱动器('w:')映射到远程计算机
    //使用cmd.exe / c dir在远程计算机上执行dir
    //注意:驱动器号是相对于远程计算机的。 (psexec -w参数)
  2. psexec \\\\<IPAddress> -i /accepteula -w "c:\\windows\\system32" cmd.exe "/c dir q:\\video /OD /TC /B > q:\\dir.txt"
  3. //读取“ w:\\ dir.txt”的第一行以获取该目录中最旧的文件。
  4. //使用windows.WNetCancelConnection2与远程计算机断开连接

您也可以尝试使用带有FindExInfoBasic参数的FindFirstFileEx ,在Windows 7或Server 2008 R2或更高版本上,可以使用FIND_FIRST_EX_LARGE_FETCH提高性能

首先,从本页获取RunDosAppPipedToTStrings例程,以了解如何运行DOS程序并将其输出通过管道传递到TStrings 该示例使用TMemo的Lines属性,但是您可以传入任何TString,例如TStringList。 请注意,如果CreateProcess返回false,这将以静默方式失败。 您可能想将一个else案例添加到引发异常的“ if CreateProcess”块中。

然后在与EXE相同的文件夹中创建一个简单的批处理文件。 称之为getdir.bat 它应该说的是:

dir %1

这将生成一个目录列表,其中列出了您传递给它的任何文件夹。 不幸的是,“ dir”是DOS关键字命令,而不是程序,因此您不能直接调用它。 将其包装在批处理文件中可以避免这种情况。 这有点hack,但是行得通。 如果您找到了运行DIR的更好方法,那就更好了。

您将要使用看起来像这样的代码来调用RunDosAppPipedToTStrings:

procedure GetDirListing(dirname: string; list: TStringList);
const
   CMDNAME = '%s\getdir.bat "%s"';
var
   path: string;
begin
  list.Clear;
  path := ExcludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0)));
  RunDosAppPipedToTStrings(format(CMDNAME, [path, dirname]), list, false);
end;

然后剩下要做的就是解析输出,提取日期和时间以及文件名,按日期和时间排序,并获取日期最低的文件名。 我会给你那么多。

如果您可以在可以遍历目录的远程计算机上运行某些内容,那将是最快的方法。 如果要使用Mason的示例,请尝试使用SysInternals的PsExec启动它。

如果您只能在本地运行应用程序,那么没有,没有比FindFirst / FindNext更快的方法了,您所做的任何其他事情最终都会归结为这种情况。 如果本地计算机运行的是Windows 7,则可以改用FindFirstFileEx ,它具有标志来指示它应为传输使用较大的缓冲区,并且不应该读取8.3别名,这可以帮助提高速度。

在开发的传真服务器软件上,我遇到了几乎相同的问题。 我必须按照从数千个传真接收到的顺序发送传真(所有传真都存储在目录中)。 我采用的解决方案(启动速度慢但运行速度快)是使用以下命令列出所有文件的排序列表

SearchRec.Time 

作为关键。 在列表中找到文件后,我将文件的属性设置为faSysFile:

NewAttributes := Attributes or faSysFile;

现在,当我用

FileAttrs := (faAnyFile and not faDirectory);

仅显示不是faSysFile的文件,因此我可以将新的文件添加到列表中。 现在,您有了一个列表,其中所有文件均按时间排序。 不要忘记,在启动应用程序时,第一步是从文件夹中的文件中删除faSysFile属性,以便可以再次处理它们。

procedure FileSetSysAttr(AFileName: string);
var
  Attributes, NewAttributes: Word;
begin
  Attributes := FileGetAttr(AFileName);
  NewAttributes := Attributes or faSysFile;
  FileSetAttr(AFileName, NewAttributes);
end;

procedure FileUnSetSysAttr(AFileName: string);
var
  Attributes, NewAttributes: Word;
begin
  Attributes := FileGetAttr(AFileName);
  NewAttributes := Attributes and not faSysFile;
  FileSetAttr(AFileName, NewAttributes);
end;

procedure PathUnSetSysAttr(APathName: string);
var
  sr: TSearchRec;
  FileAttrs: Integer;
begin
  FileAttrs := (faAnyFile and not faDirectory) and (faAnyFile or faSysFile);
  APathName := IncludeTrailingBackslash(APathName);
  if SysUtils.FindFirst(APathName + '*.*', FileAttrs, sr) = 0 then
  try
    repeat
      if (sr.Attr and faDirectory) = 0 then
        FileUnSetSysAttr(APathName + sr.Name);
    until SysUtils.FindNext(sr) <> 0;
  finally
    SysUtils.FindClose(sr);
  end;
end;

我知道这不是最佳解决方案,但对我有用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM