我在AX 2009中编写了代码,以每1秒钟在网络驱动器上进行轮询目录,等待来自另一个系统的响应文件。我注意到使用文件资源管理器窗口,我可以看到文件显示,但是我的代码在文件显示后几秒钟没有看到和处理文件 - 最多9秒(和9个民意调查)!
使用ClrInterop
:
System.IO.Directory::GetFiles()
interopPerm = new InteropPermission(InteropKind::ClrInterop);
interopPerm.assert();
files = System.IO.Directory::GetFiles(#POLLDIR,'*.csv');
// etc...
CodeAccessPermission::revertAssert();
经过大量的实验,它出现了我程序一生中的第一次,我称::GetFiles()
的名字,它以10秒的时间开始了一个名义上的"滴答时钟"。每10秒钟只能拨打每10秒即可出现的任何新文件,尽管它们确实报告了自第一个拨打::GetFiles()
以来的10s" tick"上发现的文件。
如果,当我启动程序时,该文件不存在,则所有其他呼叫 ::GetFiles()
,第一个呼叫后1秒钟,后2秒钟,等等,最多9秒,只是看不到文件,即使自第一次通话后0.5秒起可能坐在那里!
然后,可靠地,重复地,第一个呼叫后的10次通话将找到该文件。那么,从11到19s的任何电话都不会看到任何可能出现的新文件,但是第一个呼叫后的20次呼叫将可靠地看到任何新文件。等等,每10秒。
进一步的调查显示,如果轮询目录在AX AOS计算机上,则不会发生,并且在文件出现在目录中后的呼叫时,该文件立即在呼叫上找到。
。但是,无论我在哪种服务器上进行哪种网络驱动器,这10s的数字都是可靠且可重复的。
我们的网络当然没有10秒的延迟来查看文件;正如我所说,轮询目录上的文件资源管理器窗口立即看到该文件。
发生了什么?
听起来您的问题是由SMB缓存引起的 - 来自此技术页面:
名称,类型和ID
目录缓存[dword] Directorycachelifetime注册表密钥缓存设置由
HKEY_LOCAL_MACHINESystemCurrentControlSetServicesLanmanworkstationParameters
这是最新目录枚举的缓存 客户。随后由客户应用程序提出的枚举请求为 以及目录中有关文件的元数据查询 从缓存。客户端还使用目录缓存来确定 目录中的文件存在或不存在 信息以防止客户反复试图打开 已知服务器上不存在的文件。这个缓存可能是 影响在多台计算机上运行的分布式应用程序 访问服务器上的一组文件 - 应用程序使用 避免频段机制,以互相发出信号 修改/添加/删除服务器上的文件。
简而言之尝试设置注册表密钥
HKEY_LOCAL_MACHINESystemCurrentControlSetServicesLanmanworkstationParametersDirectoryCacheLifetime
到0
感谢@jan B. Kjeldsen,我能够使用filesystemwatcher解决我的问题。这是我在X 中的实现:
class SelTestThreadDirPolling
{
}
public server static Container SetStaticFileWatcher(str _dirPath,str _filenamePattern,int _timeoutMs)
{
InteropPermission interopPerm;
System.IO.FileSystemWatcher fw;
System.IO.WatcherChangeTypes watcherChangeType;
System.IO.WaitForChangedResult res;
Container cont;
str fileName;
str oldFileName;
str changeType;
;
interopPerm = new InteropPermission(InteropKind::ClrInterop);
interopPerm.assert();
fw = new System.IO.FileSystemWatcher();
fw.set_Path(_dirPath);
fw.set_IncludeSubdirectories(false);
fw.set_Filter(_filenamePattern);
watcherChangeType = ClrInterop::parseClrEnum('System.IO.WatcherChangeTypes', 'Created');
res = fw.WaitForChanged(watcherChangeType,_timeoutMs);
if (res.get_TimedOut()) return conNull();
fileName = res.get_Name();
//ChangeTypeName can be: Created, Deleted, Renamed and Changed
changeType = System.Enum::GetName(watcherChangeType.GetType(), res.get_ChangeType());
fw.Dispose();
CodeAccessPermission::revertAssert();
if (changeType == 'Renamed') oldFileName = res.get_OldName();
cont += fileName;
cont += changeType;
cont += oldFileName;
return cont;
}
void waitFileSystemWatcher(str _dirPath,str _filenamePattern,int _timeoutMs)
{
container cResult;
str filename,changeType,oldFilename;
;
cResult=SelTestThreadDirPolling::SetStaticFileWatcher(_dirPath,_filenamePattern,_timeoutMs);
if (cResult)
{
[filename,changeType,oldFilename]=cResult;
info(strfmt("filename=%1, changeType=%2, oldFilename=%3",filename,changeType,oldFilename));
}
else
{
info("TIMED OUT");
}
}
void run()
{;
this.waitFileSystemWatcher(@'\myservermydir','filepattern*.csv',10000);
}
我应该确认以下内容,以形成我的X 实现的基础:
https://blogs.msdn.microsoft.com/floditt/2008/09/01/how-to-mimplement-filesystemystemwatcher-with-with-x/
我猜达克萨利(Daxaholic)的答案是正确的,但是您可以尝试其他解决方案(例如
在您的情况下,我宁愿等待文件而不是对文件进行轮询。使用Filesystemwatcher,从文件创建到您的流程醒来将有很小的延迟。使用更棘手,但是避免进行投票是好东西。我从来没有通过网络使用它。