我在AX 2009中编写了代码,每1秒在网络驱动器上轮询一个目录,等待另一个系统的响应文件。我注意到,使用一个文件资源管理器窗口,我可以看到文件出现,但我的代码没有看到和处理文件数秒钟-长达9秒(和9轮投票)后,文件出现!
AX代码使用System.IO.Directory::GetFiles()调用ClrInterop
interopPerm = new InteropPermission(InteropKind::ClrInterop);
interopPerm.assert();
files = System.IO.Directory::GetFiles(#POLLDIR,'*.csv');
// etc...
CodeAccessPermission::revertAssert();经过大量的实验,我发现在我的程序生命周期中第一次,我称之为::GetFiles(),它以10秒的时间启动了一个概念上的“滴答时钟”。只有每10秒调用一次,才能找到可能出现的任何新文件,尽管它们仍然报告自第一次调用::GetFiles()以来在较早的10秒“滴答”中找到的文件。
如果当我启动程序时,文件不在那里,那么所有其他对::GetFiles()的调用,在第一次调用后1秒,在2秒之后,最多在9秒之后,就不能看到该文件,即使它可能在第一次调用后0.5s就一直在那里!
然后,在第一次调用之后,可靠且可重复地调用10s,将找到该文件。然后,11到19 s之间的呼叫将不会看到任何可能出现的新文件,然而在第一次呼叫之后的20多个呼叫将可靠地看到任何新文件。以此类推,每10秒。
进一步的调查发现,如果轮询目录位于AX AOS机器上,则不会发生这种情况,而且正如人们所预期的那样,在文件出现在目录中之后的调用中,将立即找到该文件。
但是这个10秒的数字是可靠的和可重复的,不管我调查什么网络驱动器,不管它在哪台服务器上。
我们的网络当然没有10s的延迟来查看文件;正如我所说的,轮询目录上的文件资源管理器窗口会立即看到文件。
怎么一回事?
发布于 2017-02-16 22:02:35
我想DAXaholic的答案是正确的,但是您可以尝试其他解决方案,比如EnumerateFiles。
在您的情况下,我宁愿等待文件,而不是投票的文件。使用FileSystemWatcher,从创建文件到进程苏醒都会有最小的延迟。使用起来更棘手,但避免轮询是一件好事。我从来没有通过网络使用过它。
发布于 2017-02-16 19:04:08
听起来您的问题是由于SMB缓存-来自这个technet页面。
名称、类型和ID 目录Cache DWORD DirectoryCacheLifetime 缓存设置由
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Lanmanworkstation\Parameters控制 这是客户端执行的最近目录枚举的缓存。客户端应用程序发出的后续枚举请求以及对目录中文件的元数据查询都可以从缓存中得到满足。客户端还使用目录缓存来确定目录中是否存在文件,并使用该信息防止客户端重复尝试打开服务器上已知不存在的文件。此缓存可能会影响在多台计算机上运行的分布式应用程序,这些应用程序访问服务器上的一组文件--其中应用程序使用带外机制相互发送修改/添加/删除服务器上文件的信号。
简而言之,尝试设置注册表项。
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Lanmanworkstation\Parameters\DirectoryCacheLifetime
转到0
发布于 2017-02-17 11:04:38
感谢@JanB.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(@'\\myserver\mydir','filepattern*.csv',10000);
}对于构成我的X++实现的基础,我应该承认以下几点:
https://blogs.msdn.microsoft.com/floditt/2008/09/01/how-to-implement-filesystemwatcher-with-x/
https://stackoverflow.com/questions/42279314
复制相似问题