c#无法打开文件进行读取
我正在编写一个程序,它使用c#无法打开文件进行读取,c#,C#,我正在编写一个程序,它使用FileSystemWatcher监视对给定目录的更改,当它接收到OnCreated或OnChanged事件时,它会将那些创建/更改的文件复制到指定目录。起初,我对OnChanged/OnCreated事件可以发送两次(如果需要处理500MB文件,则不可接受)这一事实存在问题,但我设法解决了这一问题,我真正被阻止的是获得以下IOException: 进程无法访问文件“C:\Where are Photos\bookmarks(11).html”,因为另一个进程正在使用该
FileSystemWatcher
监视对给定目录的更改,当它接收到OnCreated或OnChanged事件时,它会将那些创建/更改的文件复制到指定目录。起初,我对OnChanged/OnCreated事件可以发送两次(如果需要处理500MB文件,则不可接受)这一事实存在问题,但我设法解决了这一问题,我真正被阻止的是获得以下IOException
:
进程无法访问文件“C:\Where are Photos\bookmarks(11).html”,因为另一个进程正在使用该文件
因此,防止程序复制它应该复制的所有文件。
正如我提到的,当用户使用这个程序时,他/她指定了监控目录,当用户复制/创建/更改该目录中的文件时,程序应该得到OnCreated/OnChanged事件,然后将该文件复制到其他几个目录。
上述错误在所有情况下都会发生,前提是用户复制了几个需要覆盖被监视文件夹中其他文件的文件,或者复制了多个文件的大容量,甚至有时复制了被监视目录中的一个文件。
整个程序相当大,所以我将发送最重要的部分。
一旦创建:
private void OnCreated(object source, FileSystemEventArgs e) {
AddLogEntry(e.FullPath, "created", "");
// Update last access data if it's file so the same file doesn't
// get processed twice because of sending another event.
if (fileType(e.FullPath) == 2) {
lastPath = e.FullPath;
lastTime = DateTime.Now;
}
// serves no purpose now, it will be remove soon
string fileName = GetFileName(e.FullPath);
// copies file from source to few other directories
Copy(e.FullPath, fileName);
Console.WriteLine("OnCreated: " + e.FullPath);
}
一旦更改:
private void OnChanged(object source, FileSystemEventArgs e) {
// is it directory
if (fileType(e.FullPath) == 1)
return; // don't mind directory changes itself
// Only if enough time has passed or if it's some other file
// because two events can be generated
int timeDiff = ((TimeSpan)(DateTime.Now - lastTime)).Seconds;
if ((timeDiff < minSecsDiff) && (e.FullPath.Equals(lastPath))) {
Console.WriteLine("-- skipped -- {0}, timediff: {1}", e.FullPath, timeDiff);
return;
}
// Update last access data for above to work
lastPath = e.FullPath;
lastTime = DateTime.Now;
// Only if size is changed, the rest will handle other handlers
if (e.ChangeType == WatcherChangeTypes.Changed) {
AddLogEntry(e.FullPath, "changed", "");
string fileName = GetFileName(e.FullPath);
Copy(e.FullPath, fileName);
Console.WriteLine("OnChanged: " + e.FullPath);
}
}
副本:
这是工作,因为我可以告诉(测试),但。。。这是黑客,更不用说其他的缺陷了
我可以尝试的另一个“解决方案”(我还没有测试它)是在fileType()
方法末尾的某处使用GC.Collect()
。也许比上一个更糟糕的“解决方案”
有人能告诉我,到底是什么在锁定文件,阻止它打开,我该如何修复?我错过了什么
提前感谢。问题很可能是您已经尝试访问该文件,但仍在复制该文件。这种情况可能会发生,尤其是在大型文件上 在实际开始处理之前,您可以尝试检查是否可以使用写入权限打开该文件。有关如何执行该检查的详细信息
如果您可以影响创建文件的过程,可能会有更好的解决方案。首先使用临时扩展名复制文件,然后在复制完成后重命名文件,以便触发
FileSystemWatcher
事件。您可以尝试使用卷影复制。
有关详细信息,请参见www.codeproject.com/KB/dotnet/makeshadowcopy.aspx。文件系统监视程序事件在文件开始复制时触发,而不是在文件结束时触发,因此经常会遇到此类错误 但是,您的第一种方法是可行的,我建议在另一个线程上旋转I/O密集型代码,并使用增量Sleep()而不是繁忙的等待
但是,如果您可以访问实际创建文件的软件,那么更改扩展名是一个稍微不那么复杂的解决方案。请注意,
FileSystemwatcher
上的xls
过滤器将匹配名为myfile1.xls.temp
的文件,因为我发现了困难的方法:)非常感谢快速响应,但我不需要写权限,我需要读取权限,以便可以从中读取文件并将其复制到其他目标。@Maks:当您可以写入文件时,您也可以读取它。如果您永远无法写入,例如,因为文件夹受到保护,您也可以尝试以只读方式打开文件。我的意思是,如果是windows进程(复制)而不是写入权限(因为在事件发生时未完成),则获取读取权限可能“更容易”(可能比写入权限更容易):)你的解决方案看起来有点像我的第一个“解决方案”。如果我找不到更好(更干净)的东西,我会用类似的东西。再次感谢:)谢谢斯维科。正如我所注意到的,FSW在文件写入(0字节)时触发,然后在复制过程结束时第二次触发,因为文件大小将从0更改为原始大小。我想我需要使用第一种方法,当然需要一些延迟时间。如果我找不到锁定文件的原因以及如何解决这个问题,这是我最后的办法。
private int fileType(string path) {
if (Directory.Exists(path))
return 1; // directory
else if (File.Exists(path))
return 2; // file
else
return 0;
}
private void Copy(string srcPath, string fileName) {
foreach (string dstDirectoy in paths) {
string eventType = "copied";
string error = "noerror";
string path = "";
string dirPortion = "";
// in case directory needs to be made
if (srcPath.Length > fsw.Path.Length) {
path = srcPath.Substring(fsw.Path.Length,
srcPath.Length - fsw.Path.Length);
int pos = path.LastIndexOf('\\');
if (pos != -1)
dirPortion = path.Substring(0, pos);
}
if (fileType(srcPath) == 1) {
try {
Directory.CreateDirectory(dstDirectoy + path);
//Directory.CreateDirectory(dstDirectoy + fileName);
eventType = "created";
} catch (IOException e) {
eventType = "error";
error = e.Message;
}
} else {
try {
if (!overwriteFile && File.Exists(dstDirectoy + path))
continue;
// create new dir anyway even if it exists just to be sure
Directory.CreateDirectory(dstDirectoy + dirPortion);
// copy file from where event occured to all specified directories
using (FileStream fsin = new FileStream(srcPath, FileMode.Open, FileAccess.Read, FileShare.Read)) {
using (FileStream fsout = new FileStream(dstDirectoy + path, FileMode.Create, FileAccess.Write)) {
byte[] buffer = new byte[32768];
int bytesRead = -1;
while ((bytesRead = fsin.Read(buffer, 0, buffer.Length)) > 0)
fsout.Write(buffer, 0, bytesRead);
}
}
} catch (Exception e) {
if ((e is IOException) && (overwriteFile == false)) {
eventType = "skipped";
} else {
eventType = "error";
error = e.Message;
// attempt to find and kill the process locking the file.
// failed, miserably
System.Diagnostics.Process tool = new System.Diagnostics.Process();
tool.StartInfo.FileName = "handle.exe";
tool.StartInfo.Arguments = "\"" + srcPath + "\"";
tool.StartInfo.UseShellExecute = false;
tool.StartInfo.RedirectStandardOutput = true;
tool.Start();
tool.WaitForExit();
string outputTool = tool.StandardOutput.ReadToEnd();
string matchPattern = @"(?<=\s+pid:\s+)\b(\d+)\b(?=\s+)";
foreach (Match match in Regex.Matches(outputTool, matchPattern)) {
System.Diagnostics.Process.GetProcessById(int.Parse(match.Value)).Kill();
}
Console.WriteLine("ERROR: {0}: [ {1} ]", e.Message, srcPath);
}
}
}
AddLogEntry(dstDirectoy + path, eventType, error);
}
}
private int fileType(string path) {
FileStream fs = null;
int ret = 0;
bool run = true;
if (Directory.Exists(path))
ret = 1;
else {
while (run) {
try {
fs = new FileStream(path, FileMode.Open);
ret = 2;
run = false;
} catch (IOException) {
} finally {
if (fs != null) {
fs.Close();
fs.Dispose();
}
}
}
}
return ret;
}