【发布时间】:2015-08-10 17:48:37
【问题描述】:
我正在分块读取源文件并将其传递给 WCf 服务以在某个远程 SMB 上写下来。我一直打开 FileStream 直到所有数据都被写入。
多次打开和关闭文件句柄会降低性能,所以我采用这种方法。
所有数据写入后,我调用 CloseHandle()。然后我可能需要通过调用 DoSomeOperation() 对同一个文件执行一些其他操作。因为我在 CloseHandle() 函数中关闭了文件句柄,但在 DoSomeOperation() 中出现错误“文件正在与其他进程一起使用”。如果我在延迟一段时间后调用 DoSomeOperation() 则问题不存在。
请帮助我们在我调用 FileStream.Close() 时立即关闭文件句柄。
这段代码sn-p是一个大程序的一部分,这里就不一一列举了。
//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;
}
}
【问题讨论】:
-
尝试在所有 fs.Close() 方法之前添加 fs.Flush()。让我们知道这是否有效。
-
如果您有防病毒软件,您可以尝试禁用它以进行测试吗?
-
我立即怀疑这样的代码,其中
fs是一个共享变量。例如。如果在同一实例上有两个同时调用AppendBytes,他们可能都观察到fs为空,都打开一个新的Stream,都竞争设置fs,并且您泄漏一个流直到它的垃圾被收集.这是否可能在这里很难说,并且取决于您的实例化/线程选项。 -
您是否尝试禁用防病毒软件?
-
嗯,关于 WCF 的事情是,对于每个客户端调用,通常都会创建一个新的服务实例。您确定将 WCF 配置为使用静态实例吗?在任何其他情况下,
CloseHandle将不执行任何操作,因为fs为 null,并且该文件将从第一个服务实例开始保持打开状态,因为它永远不会关闭。