【发布时间】:2013-11-15 18:10:52
【问题描述】:
我有 10,000 个 XML 文件要读取并保存到数据库的场景。我拥有的是 5 个 Windows 服务,它们都在尝试处理该文件夹。
我的技术是首先尝试重命名 (File.Move) 文件,并使用特定于给定服务实例的扩展名。
这是 99% 的时间。但是我看到的是文件系统将在 0.01% 的情况下允许两个请求同时尝试和重命名。
如何防止这种情况发生?这有意义吗?请参阅以下代码 sn-p 了解一下。我最终得到了大约 10 个 IO 异常文件。
string[] sourceFiles = Directory.GetFiles(InputPath, string.Format(LocaleHelper.Culture, "*.{0}", Extention))
.OrderBy(d => new FileInfo(d).CreationTime).ToArray();
foreach (string file in sourceFiles)
{
var newFileName = string.Format(LocaleHelper.Culture, "{0}.{1}", file, CacheFlushManager.GetInstanceName);
try
{
// first we'll rename // however at this point the file may not even exist
// it will throw an exception and move onto the next file if it exists
File.Move(file, newFileName);
var xml = File.ReadAllText(newFileName);
// write to DB at this point we know its unique
}
catch (FileNotFoundException ex)
{
Logger.LogDebug(string.Format(LocaleHelper.Culture, "{0} Couldn't read file : {1}", CacheFlushManager.GetInstanceName, newFileName));
}
catch (IOException ex)
{
Logger.LogDebug(string.Format(LocaleHelper.Culture, "{0} Couldn't process file : {1}", CacheFlushManager.GetInstanceName, newFileName));
}
catch (Exception ex)
{
Logger.LogError("Execute: Error", ex);
try
{
File.Move(newFileName, string.Format(LocaleHelper.Culture, "{0}.badfile", newFileName));
}
catch (Exception ex_deep)
{
Logger.LogError(string.Format("{0} Execute: Error Deep could not move bad file {1}", CacheFlushManager.GetInstanceName, newFileName), ex_deep);
}
}
编辑 1
以下是我所看到的确切错误示例。我对文件如何根据我正在使用的代码使用确切的时间感到非常困惑?我是否完全摆脱了这个困境?
[7220] TransactionFileServiceProcess [11:28:32]:Service4 无法处理文件:C:\temp\Input\yap804.xml.Service4 System.IO.IOException:进程无法访问文件'C:\ temp\Input\yap804.xml.Service4' 因为它正被另一个进程使用。
编辑 2
这里是从“调试”的角度来看正在发生的事情。 Service 的 2 和 3 怎么会到达“END RENAME”?我认为这是问题的症结所在......想法?
问题在于文件yap620.xml.Service3 最终会因为文件操作错误而被搁置。
[6708] TransactionFileServiceProcess [10:54:38]: Service3 Start Rename: C:\temp\Input\yap620.xml.Service3 TransactionFileServiceProcess.Execute => BHSLogger.LogDebug => LoggerImpl.Write E[]
[4956] TransactionFileServiceProcess [10:54:38]: Service2 Start Rename: C:\temp\Input\yap620.xml.Service2 TransactionFileServiceProcess.Execute => BHSLogger.LogDebug => LoggerImpl.Write E[]
[7416] TransactionFileServiceProcess [10:54:38]: Service4 Start Rename: C:\temp\Input\yap620.xml.Service4 TransactionFileServiceProcess.Execute => BHSLogger.LogDebug => LoggerImpl.Write E[]
[6708] TransactionFileServiceProcess [10:54:38]: Service3 End Rename: C:\temp\Input\yap620.xml.Service3 TransactionFileServiceProcess.Execute => BHSLogger.LogDebug => LoggerImpl.Write E[]
[6708] TransactionFileServiceProcess [10:54:38]: Service3 Start Read: C:\temp\Input\yap620.xml.Service3 TransactionFileServiceProcess.Execute => BHSLogger.LogDebug => LoggerImpl.Write E[]
[4956] TransactionFileServiceProcess [10:54:38]: Service2 End Rename: C:\temp\Input\yap620.xml.Service2 TransactionFileServiceProcess.Execute => BHSLogger.LogDebug => LoggerImpl.Write E[]
[4956] TransactionFileServiceProcess [10:54:38]: Service2 Start Read: C:\temp\Input\yap620.xml.Service2 TransactionFileServiceProcess.Execute => BHSLogger.LogDebug => LoggerImpl.Write E[]
[6708] TransactionFileServiceProcess [10:54:38]: Service3 Couldn't process file : C:\temp \Input\yap620.xml.Service3 TransactionFileServiceProcess.Execute => BHSLogger.LogDebug => LoggerImpl.Write E[]
【问题讨论】:
-
10,000 个 XML 文件?为什么不使用 JSON?
-
不幸的是,我无法选择它们的文件格式。在这种情况下,这无关紧要。
-
试图消除冲突是没有意义的——你似乎已经有足够的代码来避免它——所以只要期待发生冲突(或任何其他 IO 错误)并重试。
-
您的意思是您有五个服务在同一个文件夹上同时执行此操作?
-
你是说
File.Move方法对于尝试重命名同一个文件的两个不同进程成功了吗?这似乎不太可能。
标签: c# multithreading windows-services