独家打开/修改XML文件?

时间:2022-01-13 07:45:38

I need to open an XML file exclusively, make a modification, and save it.

我需要专门打开一个XML文件,进行修改并保存。

I can open it and make the modification pretty easily like so:

我可以打开它并很容易地进行修改:

DataSet ds = new DataSet();
ds.ReadXml(filename);

DataTable table = ds.Tables[0];
DataRow[] rows = table.Select("Inventory== 1");
DataRow row = rows[0];
row["Inventory"] = "2";
ds.WriteXml(filename);

That all works great, but it doesn't lock the file. I absolutely need the file locked.

这一切都很好,但它不会锁定文件。我绝对需要锁定文件。

So I tried it with a stream:

所以我用一个流尝试了它:

FileStream stream = File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.None);

DataSet ds = new DataSet();
ds.ReadXml(stream);

DataTable table = ds.Tables[0];
DataRow[] rows = table.Select("Inventory== 1");
DataRow row = rows[0];
row["Inventory"] = "2";
ds.WriteXml(stream);
stream.Close();

That opens the file exclusively, but when it saves, it appends the XML to the end of the time, it doesn't overwrite it, so I end up with something like:

这会以独占方式打开文件,但是当它保存时,它会将XML附加到时间结束,它不会覆盖它,所以我最终得到的结果如下:

<Widgets>
  <Widget Code="5" Number="10" Inventory="1" />
  <Widget Code="6" Number="11" Inventory="15" />
  <Widget Code="7" Number="12" Inventory="22" />
</Widgets>
<Widgets>
   <Widget Code="5" Number="10" Inventory="2" />
  <Widget Code="6" Number="11" Inventory="15" />
  <Widget Code="7" Number="12" Inventory="22" />
</Widgets>

What I want is:

我想要的是:

<Widgets>
  <Widget Code="5" Number="10" Inventory="2" />
  <Widget Code="6" Number="11" Inventory="15" />
  <Widget Code="7" Number="12" Inventory="22" />
</Widgets>

I know I could open the file and use the File methods to parse it line by line and make my change... but I was hoping for something more elegant. The first method - loading the file using ReadXml - does the file modification just fine, but it doesn't appear to have any options for opening the file exclusively. Am I missing something?

我知道我可以打开文件并使用File方法逐行解析它并进行更改...但我希望有更优雅的东西。第一种方法 - 使用ReadXml加载文件 - 文件修改很好,但似乎没有任何选项可以独占打开文件。我错过了什么吗?

2 个解决方案

#1


5  

In your stream, you need to reset the stream's head to the beginning of the file AND erase existing content to overwrite existing data in case your replacement text is shorter than the original content. Try placing this before ds.writeXml:

在流中,您需要将流的头部重置为文件的开头并删除现有内容以覆盖现有数据,以防替换文本短于原始内容。尝试在ds.writeXml之前放置它:

stream.Seek(0, SeekOrigin.Begin);
stream.SetLength(0);

The first line moves the head, the second truncates the file so if what you are replacing the text with is shorter than the original text, you will not have extraneous characters at the end.

第一行移动头部,第二行截断文件,因此如果要替换文本的内容比原始文本短,则最后不会有无关的字符。

Note that, as Reed Copsey points out, it might be better to do the write first, then set the length to the stream's Position member, as this will have no effect in the event that the replacing text is the same length or longer than the text replaced, which might be marginally more efficient.

请注意,正如Reed Copsey所指出的那样,首先执行写入可能会更好,然后将长度设置为流的Position成员,因为如果替换文本的长度与长度相同或长于此值,则无效。替换了文本,这可能会略微提高效率。

#2


6  

You can do it with a stream, but you need to reset your stream before writing:

您可以使用流来执行此操作,但需要在写入之前重置您的流:

using(FileStream stream = File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
{
    DataSet ds = new DataSet();
    ds.ReadXml(stream);

    DataTable table = ds.Tables[0];
    DataRow[] rows = table.Select("Inventory== 1");
    DataRow row = rows[0];
    row["Inventory"] = "2";

    // Reset the stream here to the beginning of the file!
    stream.Seek(0, SeekOrigin.Begin);
    ds.WriteXml(stream);
    // Reset the length of the stream prior to closing it, in case it's shorter than it used to be...
    stream.SetLength(stream.Position);
}

#1


5  

In your stream, you need to reset the stream's head to the beginning of the file AND erase existing content to overwrite existing data in case your replacement text is shorter than the original content. Try placing this before ds.writeXml:

在流中,您需要将流的头部重置为文件的开头并删除现有内容以覆盖现有数据,以防替换文本短于原始内容。尝试在ds.writeXml之前放置它:

stream.Seek(0, SeekOrigin.Begin);
stream.SetLength(0);

The first line moves the head, the second truncates the file so if what you are replacing the text with is shorter than the original text, you will not have extraneous characters at the end.

第一行移动头部,第二行截断文件,因此如果要替换文本的内容比原始文本短,则最后不会有无关的字符。

Note that, as Reed Copsey points out, it might be better to do the write first, then set the length to the stream's Position member, as this will have no effect in the event that the replacing text is the same length or longer than the text replaced, which might be marginally more efficient.

请注意,正如Reed Copsey所指出的那样,首先执行写入可能会更好,然后将长度设置为流的Position成员,因为如果替换文本的长度与长度相同或长于此值,则无效。替换了文本,这可能会略微提高效率。

#2


6  

You can do it with a stream, but you need to reset your stream before writing:

您可以使用流来执行此操作,但需要在写入之前重置您的流:

using(FileStream stream = File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
{
    DataSet ds = new DataSet();
    ds.ReadXml(stream);

    DataTable table = ds.Tables[0];
    DataRow[] rows = table.Select("Inventory== 1");
    DataRow row = rows[0];
    row["Inventory"] = "2";

    // Reset the stream here to the beginning of the file!
    stream.Seek(0, SeekOrigin.Begin);
    ds.WriteXml(stream);
    // Reset the length of the stream prior to closing it, in case it's shorter than it used to be...
    stream.SetLength(stream.Position);
}