我在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.5秒就坐在那里!
然后,可靠且可重复地,在第一次呼叫之后的呼叫10s将找到该文件。然后,从11s到19s的任何呼叫都不会看到可能出现的任何新文件,但是在第一次呼叫后20s的呼叫将可靠地看到任何新文件。等等,每10秒钟一次。
进一步调查显示,如果轮询目录位于AX AOS计算机上,则不会发生这种情况,并且在文件出现在目录中后,会立即找到该文件(如预期的那样)。
但这个10s的数字是可靠且可重复的,无论我使用什么网络驱动器进行轮询,无论它在哪个服务器上。
我们的网络肯定没有10秒的延迟来查看文件;正如我所说,轮询目录上的文件浏览器窗口会立即看到该文件。
发生了什么事?
答案 0 :(得分:2)
听起来您的问题是由于SMB缓存 - 来自this technet page:
名称,类型和ID
目录缓存[DWORD] DirectoryCacheLifetime注册表项缓存设置由
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Lanmanworkstation\Parameters
这是由最近执行的目录枚举的缓存 客户。客户端应用程序作为后续枚举请求 以及可以满足目录中文件的元数据查询 从缓存。客户端还使用目录高速缓存来确定 目录中是否存在文件并使用该文件 防止客户反复尝试打开的信息 已知服务器上不存在的文件。这个缓存很可能 影响在多台计算机上运行的分布式应用程 访问服务器上的一组文件 - 应用程序使用的文件 带外机制相互发出信号 修改/添加/删除服务器上的文件。
简而言之,尝试设置注册表项
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Lanmanworkstation\Parameters\DirectoryCacheLifetime
到0
答案 1 :(得分:2)
感谢@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(@'\\myserver\mydir','filepattern*.csv',10000);
}
我应该承认以下内容构成了我的X ++实现的基础:
https://blogs.msdn.microsoft.com/floditt/2008/09/01/how-to-implement-filesystemwatcher-with-x/
答案 2 :(得分:1)
我猜DAXaholic的答案是正确的,但您可以尝试其他解决方案,例如EnumerateFiles。
在您的情况下,我宁愿等待文件而不是轮询文件。 使用FileSystemWatcher,从文件创建到您的进程唤醒将会有最小的延迟。使用起来比较棘手,但避免轮询是好事。我从未在网络上使用它。