用Delphi实现文件读取超时

用Delphi实现文件读取超时,delphi,file-io,timeout,delphi-2006,Delphi,File Io,Timeout,Delphi 2006,我有一个用Delphi 2006编写的应用程序,它定期从位于网络其他位置的磁盘文件(100Mb以太网)中读取数据。偶尔,通过网络进行读取需要很长时间(比如20秒),应用程序会冻结,因为读取是从主线程中的空闲处理程序完成的 好的,我可以将读取操作放在它自己的线程中,但我想知道的是,是否可以为文件操作指定一个超时,这样您就可以放弃并去做其他事情,或者报告读取在20秒后稍早发生故障的事实 function ReadWithTimeout (var Buffer ;

我有一个用Delphi 2006编写的应用程序,它定期从位于网络其他位置的磁盘文件(100Mb以太网)中读取数据。偶尔,通过网络进行读取需要很长时间(比如20秒),应用程序会冻结,因为读取是从主线程中的空闲处理程序完成的

好的,我可以将读取操作放在它自己的线程中,但我想知道的是,是否可以为文件操作指定一个超时,这样您就可以放弃并去做其他事情,或者报告读取在20秒后稍早发生故障的事实

function ReadWithTimeout (var Buffer     ;
                              N       : integer ; 
                              Timeout : integer) : boolean ;

begin
Result := false
try
    SetReadTimeout (Timeout) ;          //  <==========================???
    FileStream.Read (Buffer, N) ;
    Result := true ;
except 
    ... 
    end ;
end ;
函数ReadWithTimeout(变量缓冲区;
N:整数;
超时:整数):布尔值;
开始
结果:=假
尝试

SetReadTimeout(超时);// 将读取操作移动到线程后,可以在读取之前存储timeGetTime返回的值:

isReading := true;
try
  startedAt := timeGetTime;
  FileStream.Read (Buffer, N);
  ...
finally
  isReading := false;
end;
如果花费的时间太长,请检查空闲处理程序

例如:

函数ticksElapsed(FromTicks,ToTicks:cardinal):cardinal;
开始
如果FromTicks10*1000)//时间过长~10秒
那就做点什么

通过在调用
CreateFile
时包含
file\u标志重叠
来打开的文件。调用
ReadFile
时,将
传递给overlapped
记录,如果读取未立即完成,函数将提前返回。通过对存储在
ToOverlapped
结构中的事件调用
WaitForSingleObject
,可以控制等待读取完成的时间。您甚至可以使用
MsgWaitForMultipleObjects
等待;然后,您可以在读取完成或消息到达时收到通知,以先到者为准,因此您的程序根本不需要挂起。处理完消息后,您可以使用
GetOverlappedResult
再次检查I/O是否完成,继续等待,或者通过调用
CancelIo
放弃I/O。确保仔细阅读所有这些功能的文档;异步I/O并不简单。

问题是:如果线程中的读取遇到障碍,它将保持文件打开,因此即使我检测到它花费了1秒以上的时间,比如说,我也无法重试,直到线程到达finally子句,也就是说,直到20秒过去。嗯,根据用于打开文件的共享模式,您应该能够打开该文件的第二个句柄,并尝试与其他线程并行。“不过,对于覆盖共享数据或启动太多线程等问题,您应该小心。我肯定会的,但我会把这留给比我更有能力(或更有动力)的人,”Workshop说。正如我所说,这不是小事,所以我不打算当场编写一个示例。
function ticksElapsed( FromTicks, ToTicks : cardinal ) : cardinal;
begin
  if FromTicks < ToTicks
    then Result := ToTicks - FromTicks
    else Result := ( high(cardinal) - FromTicks ) + ToTicks; // There was a wraparound
end;

...

if isReading and ( ticksElapsed( startedAt, timeGetTime ) > 10 * 1000 ) // Taken too long? ~10s
then // Do something