2016-11-09 149 views
1

我有一个长时间运行的编译XML文件的REST API方法。用户发出启动此编译的请求,创建基本文件,然后为用户提供用于查询进度的唯一ID。读取正在写入的XML文件

当被调用时,进度读取方法以只读方式打开文件,实例化一个XDocument对象并计算其中的元素数量。

其中填充 XML文件与

using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.Read)) 
{ 
    var xmlDoc = XDocument.Load(fs); 

    foreach (...) 
    { 
     // add the element to xmlDoc 

     xmlDoc.Save(filePath); 
    } 
} 

为了读取的文件中的代码访问的代码进行计数元件的数量

using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
{ 
    var xmlDoc = XDocument.Load(fs); 

    // count elements 
} 

然而,在填充方法引发的异常xmlDoc.Save(filePath);

进程无法访问文件'...',因为它正在被另一个进程使用。

正如我的理解是,与FileShare.Read打开的FileStream允许另一个进程打开具有只读访问的文件(我相信这是发生),并同样在读/计数方法使用FileShare.ReadWrite将允许填充进程使用写入访问来打开文件。

为什么上面的代码不允许这两个进程做我期望的?

回答

2

当你调用

xmlDoc.Save(filePath) 

你通过文件名,这样XmlDocument不使用你打开了写你的fs流。相反,它会在内部打开另一个流,这当然会失败,因为您已经打开了一个用于写入的流。

相反,寻求到流的开头,然后调用

xmlDoc.Save(fs); 

您也可以设置流长度为零保存(截断旧内容)之前,虽然不能完全肯定IRS必要的。

+0

您能解释一下这个建议背后的原因:“您也可以在保存之前将流长设置为零(截断旧内容)”?在保存删除流的内容之前,是不是将流_length_设置为0?或者也许你打算写我应该把长度设置到当前位置? – awj

+0

您首先打开一个包含现有内容的流,并将该内容读入XDocument(XDocument.Load)。假设文件是​​1000字节。在保存之前,流的长度为1000,位置为1000.您试图将位置设置为0并保存。现在假设新文档的长度为900.如果XDocument.Save没有将流长度本身设置为900,那么最终可能会有900字节的新文档+以前的文档的100字节,总计为1000,而这不是您想。由于我不确定XDocument.Save如何在内部工作,所以我建议在保存之前截断流,可以肯定。 – Evk

+0

好的,要做2点:(1)写入文件的内容只会增长;打开时,FileStream永远不会比以前更短。 (2)在实现这个时,我得到了一个例外:“试图在流开始之前移动位置”。这种情况发生在看似随机的时间 - 有时是在第一次查询时读取,其他时间在很多时候。 – awj