【发布时间】:2021-12-06 07:06:39
【问题描述】:
我目前面临一个由多个组件组成的应用程序的问题。
该应用程序的一个组件会定期检查网络驱动器上的新文件并将它们复制到本地文件夹中。该应用程序的另一个组件使用FileSystemWatcher 来监视本地文件夹中的任何新文件。如果复制了新文件,则调用FileSystemWatcher 的Created 事件,然后应用程序将读取文件内容并将文件导入数据库。
为了防止应用程序在文件完全复制到本地文件夹之前尝试读取文件,它会定期调用以下函数,直到它返回false:
private bool isFileLocked(string filePath)
{
try
{
if (!File.Exists(filePath))
{
return false;
}
using (FileStream fs = File.OpenRead(filePath))
{
}
return false;
}
catch (IOException)
{
return true;
}
}
不幸的是,这似乎不适用于所有情况。有时,我注意到文件在完全写入本地文件夹之前已被读取。发生这种情况时,尝试复制文件的组件会收到以下错误:
System.IO.IOException: The process cannot access the file '...' because it is being used by another process.
复制文件的组件是用 PowerShell 编写的,并使用以下 Cmdlet 进行复制:
Copy-Item $currentfile.FullName -Destination "$destfolder" –Force -ErrorAction Stop
使用FileSystemWatcher 并导入文件的组件是基于C# 的Windows 服务。
在文件完全复制到本地文件夹之前,如何防止它读取文件?
【问题讨论】:
-
如何让你需要等待的方法“异步”?用
async和await标记他们的操作一一对应。如果线程被阻塞也没有影响,请将它们设为任务并调用Task.Wait以确保它已完成。 -
如果您尝试打开文件进行写入有什么不同吗?
-
@MatthewWatson 我不知道。这个问题很少发生(有时一两天都不会发生),所以我不能在短时间内轻松测试任何东西。
-
为了提高可靠性,我会尝试实施某种“事务性”方案。一个简单的方法是复制具有临时目标名称的文件,例如
$currentFile.FullName + '.tmp'。复制文件后,将其重命名为最终名称。当使用FileSystemWatcher的组件只关注最终名称(忽略“*.tmp”)时,可以确定文件已被完整复制。 -
@marsze 通过调用
isFileLocked来完成等待,直到它返回 false。只有在这种情况下,代码才会读取文件内容。我认为这里可能发生的情况是,在复制文件时创建和打开文件之间可能有很短的时间,所以如果在创建和打开之间调用 isFileLocked ,它将“窃取”文件访问权限并阻止复制从写入文件内容。这有意义吗?
标签: c# powershell copy-paste filesystemwatcher network-drive