[英]Quickest way to find the oldest file in a directory using Delphi
您好
我们有大量的远程计算机将视频捕获到磁盘驱动器上。 每个摄像机都有其自己的唯一目录,并且每个磁盘上最多可以有16个目录。
我正在尝试在磁盘上找到最旧的视频文件,但是使用FindFirst/FindNext
比较文件创建日期时间会花费很多时间。
有人知道在目录中查找最旧文件的更有效方法吗? 我们从中央HO位置远程连接到PC。
问候,彼得
-更新
谢谢大家的回答。 最后,我使用了以下内容。
windows.WNetAddConnection2
将驱动器('w:')映射到远程计算机 psexec \\\\<IPAddress> -i /accepteula -w "c:\\windows\\system32" cmd.exe "/c dir q:\\video /OD /TC /B > q:\\dir.txt"
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.