如何在另一个进程正在使用文件时复制该文件

47

有没有可能在另一个进程正在使用文件的同时复制该文件?

我之所以问这个问题,是因为当我尝试使用以下代码复制文件时,会引发异常:

 System.IO.File.Copy(s, destFile, true);

引发的异常是:

由于另一个进程正在使用文件“D:\ temp \ 1000000045.zip”,因此无法访问该文件。

我不想创建新文件,只是想复制或删除它。这可行吗?


你的应用程序是否阻止了该文件? - Anton Semenov
我不知道是我的应用程序阻止了它还是没有,因为我正在使用ICSharpCode.SharpZipLib.Zip引用创建一个zip文件。压缩完成后,我将其复制并导出。导出后,当我再次想要删除该文件时,就会显示异常。 - Vir
7个回答

50

一个例子(注:我只是结合了两个 Google 的结果,你可能需要修复一些小错误 )

打开 FileStream 时,关键部分是 FileShare.ReadWrite

我使用类似的代码来打开和读取 Excel 文档,而 Excel 仍然处于打开状态并阻止文件。

using (var inputFile = new FileStream(
    "oldFile.txt",
    FileMode.Open,
    FileAccess.Read,
    FileShare.ReadWrite))
{
    using (var outputFile = new FileStream("newFile.txt", FileMode.Create))
    {
        var buffer = new byte[0x10000];
        int bytes;

        while ((bytes = inputFile.Read(buffer, 0, buffer.Length)) > 0)
        {
            outputFile.Write(buffer, 0, bytes);
        }
    }
}

4
虽然您的方法是正确的,但有时无法读取被其他进程锁定的文件;正如GolezTrol所提到的,有些文件也是只读锁定的。但无论如何,您的描述仍然是正确的方法,并值得点赞。如果您能够使用.NET读取附加的MS SQL数据文件,我将很高兴学习您的方法。 - faester
8
为什么不使用inputFile.CopyTo(outputFile, 0x10000); - Marcel Popescu
当复制当前被 MS Word 打开的文件时,这个方法不起作用。 - Ariwibawa

12
为了创建一个在Windows上被另一进程锁定的文件的副本,最简单(也可能是唯一)的解决方案是使用卷影复制服务(VSS)。
卷影复制服务很复杂,难以从托管代码中调用。幸运的是,一些好心人创建了一个.NET类库来完成这项工作。请查看CodePlex上的Alpha VSS项目:http://alphavss.codeplex.com
编辑
与CodePlex上的许多项目一样,Alpha VSS已迁移到GitHub。该项目现在在此处:https://github.com/alphaleonis/AlphaVSS

6

还有一种选择是使用Process类将锁定的文件复制到其他地方,并调用CMD使用“copy”命令。在大多数情况下,“copy”命令将能够复制文件,即使它正在被另一个进程使用,从而绕过C#File.Copy问题。

示例:

try
{
File.Copy(somefile)
}
catch (IOException e)
{
 if (e.Message.Contains("in use"))
                        {

                            Process.StartInfo.UseShellExecute = false;
                            Process.StartInfo.RedirectStandardOutput = true;                           
                            Process.StartInfo.FileName = "cmd.exe";
                            Process.StartInfo.Arguments = "/C copy \"" + yourlockedfile + "\" \"" + destination + "\"";
                            Process.Start();                            
                            Console.WriteLine(Process.StandardOutput.ReadToEnd());
                            Proess.WaitForExit();
                            Process.Close();                          
                        }
}

the try/catch should be added on top of your current try/catch to handle the file in use exception to allow your code to continue... 

尽管这段代码可能回答了问题,但提供关于为什么和/或如何回答问题的额外上下文会更好。 - cSteusloff
使用复制命令无法处理被 MS Word 打开的文件。 - Ariwibawa

6
var sourceFile = new FileInfo(sourceFilePath);
sourceFile.CopyTo(destFilePath, true);

FileInfo的CopyTo方法将现有文件复制到新文件,允许覆盖现有文件。这就是为什么它不会破坏正在处理现有文件的进程。

谢谢。我之前使用了另一个问题中的方法来检查文件是否被锁定,但是它一直卡住了,导致了很多问题。现在只使用CopyTo方法就可以解决这个问题了。 - Dave Johnson
这段代码适用于由msword打开的文件,我使用了cmd复制方法并且它是有效的。直到我在Windows Server 2019(版本1809 OS Build 17763.2061)上测试我的应用程序时,之前有效的代码在Build 17763.379上无法工作。 - Ariwibawa
这绝对是一个好的、简单的解决方案。 - pianocomposer

4
你应该探索并查找哪个进程正在阻塞文件。如果这个进程不是你的,那么你没有办法解决问题。当然,你可以使用一些技巧并手动释放文件锁定,但很可能会导致意想不到的后果。如果这个进程是你的,尝试解除文件锁定或使用共享读取访问锁定它。
[编辑] 最简单的找出阻止进程的方法是使用Process Explorer。启动它并在查找->查找句柄或DLL...对话框中输入文件名。在搜索结果中,您将能够看到哪个进程正在阻塞您的文件。 您还可以在C#中完成此工作,请参阅:What process locks a file?

-2

不行,有些程序会锁定文件以供读取,如果这样的话,你就无法访问该文件,除非关闭其他程序。


4
实际上,你可以在 NTFS 文件系统中实现此功能,这也是所有备份程序能够备份打开文件的原因。它们都使用日志记录来检测变化,使用 VSS 读取仍然打开的文件,有时使用事务来确保只备份一致的文件。 - Panagiotis Kanavos
6
@PanagiotisKanavos 我认为那不是常识。如果你能在回答中详细说明,你会让我,OP以及可能还有很多人感到非常高兴。 - GolezTrol

-4

尝试:

var sourceFile = new FileInfo(sourceFilePath);
sourceFile.CopyTo(destinationFilePath, true);

你能解释一下这可能如何有帮助吗? - zaitsman
这对我起作用了,但是File.Copy没有……我没有解释。 - Gokulnath
我刚刚测试了这个方法,它对我来说没有起作用。和File.Copy一样的异常。 - Gertsen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接