C# FileStream.Close()不会立即关闭文件句柄

C# FileStream.Close()不会立即关闭文件句柄,c#,.net,C#,.net,我正在分块读取源文件,并将其传递给WCf服务,以便在一些远程SMB上进行写操作。在写入所有数据之前,我一直打开文件流 多次打开和关闭文件句柄会降低性能,所以我采用这种方法 写入所有数据后,我调用CloseHandle()。然后,我可能需要通过调用DoSomeOperation()对同一文件执行一些其他操作。由于我在CloseHandle()函数中关闭了文件句柄,但在DoSomeOperation()中出现错误“文件正在与其他进程一起使用”。若我在延迟后调用DoSomeOperation(),那个

我正在分块读取源文件,并将其传递给WCf服务,以便在一些远程SMB上进行写操作。在写入所有数据之前,我一直打开文件流

多次打开和关闭文件句柄会降低性能,所以我采用这种方法

写入所有数据后,我调用CloseHandle()。然后,我可能需要通过调用DoSomeOperation()对同一文件执行一些其他操作。由于我在CloseHandle()函数中关闭了文件句柄,但在DoSomeOperation()中出现错误“文件正在与其他进程一起使用”。若我在延迟后调用DoSomeOperation(),那个么问题就不存在了

在调用FileStream.close()时,请帮助我们立即关闭文件句柄

这段代码是一个大程序的一部分,所以我不能在这里提及所有的代码

//In WCF service
FileStream fs = null;
public void AppendBytes(string fileName, byte[] data, long position)
{
    try
    {
        if (fs==null)//In first call, open the file handle
            fs = System.IO.File.Open(fileName, System.IO.FileMode.Append, System.IO.FileAccess.Write, System.IO.FileShare.None);

        fs.Write(data, 0, data.Length);
    }
    catch (Exception ex)
    {
        //Close handle in case of error
        if (fs != null)
            fs.Close();
    }
}

public void CloseHandle()
{
    //Close handle explicitly
    if (fs != null)
        fs.Close();
}

public void DoSomeOperation(string fileName)
{
    using (FileStream fsO = System.IO.File.Open(fileName, System.IO.FileMode.Append, System.IO.FileAccess.Write, System.IO.FileShare.None))
    {
        //Do something with file here, this is atomic operation so I am opening FileStream with 'using' to dispose at operation is over
    }
}

//In client
public void CallerFunction()
{
    //Read Data from sourceFile in chunk and copy to target file using WCF.AppendBytes on another machine
    WCF.AppendBytes(filename, data, pos);
    WCF.CloseHandle();
    WCF.DoSomeOperation(filename); //I get error here that file is in use with some other process. if I put a thread.sleep(1000) just before this statement then all works fine.
}
我已经编写了一个小测试代码来在控制台应用程序上重现相同的场景:只需从Main()调用TestHandleClose(),它将在一些周期后给出错误

 static  void TestHandleClose()
        {
            int i = 0;
            try
            {

                if (File.Exists(@"d:\destination\file2.exe"))
                    File.Delete(@"d:\destination\file2.exe");

                byte[] data = null;
                int blocksize = 10 * 1024 * 1024;

                for( i=0;i<100;i++)
                {
                    using (FileStream fr = File.Open(@"d:\destination\File1.zip", FileMode.Open, FileAccess.Read, FileShare.None))
                    {
                        data = new byte[blocksize];
                        fr.Read(data, 0, blocksize); //We are reading the file single time but appending same data to target file multiple time.

                        using (FileStream f = File.Open(@"d:\destination\file2.exe", FileMode.Append, FileAccess.Write, FileShare.None))
                        {
                            f.Write(data, 0, data.Length); //We are writing same data multiple times.
                            f.Flush();
                            f.Close();
                        }
                    }

                }

                if (File.Exists(@"d:\destination\file2.exe"))
                    File.Delete(@"d:\destination\file2.exe");

            }
            catch (Exception ex)
            {
                throw;
            }
        }
static void TestHandleClose()
{
int i=0;
尝试
{
如果(File.Exists(@“d:\destination\file2.exe”))
删除(@“d:\destination\file2.exe”);
字节[]数据=null;
int blocksize=10*1024*1024;

对于(i=0;i最终的示例代码有帮助,我很确定我有您的问题

问题是,即使是最新的示例代码也无法复制。但是,它显示了另一件您可能遗漏的事情—您正在编写的文件是
.exe
。为什么会出现此问题?有两个原因,但其中之一是,当您列出
.exe
文件使用explorer的目录时,explorer会出现问题ead并尝试读取它(以获取图标)。在这么短的时间内,无法使用
FileShare.None
打开该文件(事实上,
FileShare.read
可能也不会有帮助,因为打开它的人很可能没有指定
FileShare.ReadWrite

所以再次强调,
FileStream
关闭得很好,并且运行良好(不过,要摆脱
Flush
Close
调用,它们浪费了性能,而且毫无用处)。问题是另一个进程同时尝试读取文件。可能是像我这样的文件管理器(Explorer、Total Commander,…),它可能是你的某个地方的某个
FileSystemWatcher
,它可能是一个病毒扫描器(尽管现在大多数病毒扫描器都使用卷影副本),它可能是自动为图像创建缩略图的东西,等等。但是你自己发布的代码根本不会引起问题-是其他人抓取了你的文件


基本上有两种选择——要么在需要时一直打开文件,要么将
IOException
视为临时的,并在给定的时间间隔内重试几次。无论如何,这就是你应该做的,而不是依赖于满意的路径——大多数读卡器只允许并发读取,而不允许写入。

缺少的是文件共享模式。我过去常常在短时间内读取/写入同一文件中的多个源。有时它通过良好,有时它被阻止(另一个进程正在保存该文件),即使文件流已被释放,并且我使用了锁和using().当我添加文件共享模式ReadWrite时,所有问题都解决了



尝试在所有fs.Close()之前添加fs.Flush()方法。让我们知道这是否有效。如果你有一个防病毒软件,你能试着为了测试目的禁用它吗?我立即怀疑像这样的代码,
fs
是一个共享变量。例如,如果在同一个实例上有两个同时调用
AppendBytes
,它们可能都观察到
fs
为空,都是op在一个新的
流中
,两者都竞争设置
fs
,然后你泄漏一个流,直到它的垃圾被回收。这是否可能取决于你的实例/线程选项。你试过禁用防病毒吗?嗯,关于WCF的事情是,对于每个客户端调用,通常都会创建一个新的服务实例。你呢您确定已将WCF配置为使用静态实例吗?在任何其他情况下,
CloseHandle
都不会起任何作用,因为
fs
为空,并且该文件将从第一个服务实例开始保持打开状态,因为它从未关闭。您太神奇了,它工作起来就像奇迹一样。问题只存在于扩展名.exe。I put Flush(),Close()在使用block来满足其他开发人员时。他们一直建议:)。因此,如果出现IO异常,我将尝试在循环中使用一些线程访问同一个文件句柄,最多1秒。Sleep(50)在声明该文件正被其他进程使用之前。@Romil是的,
Flush
几乎肯定会使您的性能变差-自动调用为
using
Dispose
超出范围,它会很好地处理刷新和关闭。当您
Flush
时,您基本上会说:“扔掉所有能让一切快速运行的缓冲区”(而且它甚至不能确保数据被刷新,因为它实际上是异步的,而不是阻塞的)。在关闭文件之前只刷新一次不会有什么区别,但这是不必要的,可能会让人困惑:)请阅读Luaan的答案。这是一个完全不同的场景。
using (FileStream fileStream = new FileStream(file, mode, access, FileShare.ReadWrite))
{...