2009-09-01 64 views
3

我需要專門打開一個XML文件,進行修改並保存。獨家打開/修改XML文件?

我可以很容易地打開它並進行修改,如下所示:

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); 

這一切的偉大工程,但它不鎖文件。我絕對需要鎖定文件。

所以我與流試了一下:

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(); 

這完全打開該文件,但是當它保存,它追加到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> 

我要的是:

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

我知道我可以打開文件和u se File方法逐行解析它並進行更改......但我希望能有更優雅的東西。第一種方法 - 使用ReadXml加載文件 - 文件修改很好,但它沒有任何專門打開文件的選項。我錯過了什麼嗎?

回答

5

在你流,你需要將數據流的頭復位到文件的開頭和擦除現有內容覆蓋現有數據,以防您的替換文本短於原始內容。嘗試ds.writeXml之前放置這樣的:

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

第一行移動頭部,第二截斷文件,所以如果你用替換文本比原來的文本短,你不會在多餘的字符結束。

請注意,正如Reed Copsey指出的那樣,先寫入可能會更好,然後將長度設置爲流的Position成員,因爲如果替換文本的長度相同,這將不起作用或長於替換的文本,這可能稍微更有效。

+0

太棒了!我知道它必須是簡單的,我失蹤了! – BDW 2009-09-01 17:28:21

+0

@Walt W:您也可以在寫入新數據之後調用setlength,這可能更有效(因爲如果它更長,它不會產生效果,並且如果更短,則只會重置一次長度,而不是您寫...) – 2009-09-01 17:40:16

+0

@Reed Copsey:這是真的。 – 2009-09-01 17:41:51

6

您可以用流做到這一點,但你需要前寫作重置流

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

如果新的xml比這裏的舊xml短,會發生什麼? – 2009-09-01 17:25:42

+0

不會尋求文件的開始,只要確保數據是從文件的開頭寫入的。即假設新數據大於或等於先前的數據,它將覆蓋先前的數據? – 2009-09-01 17:28:43

+1

@Walt W:+1。我忘記了進行SetLength(...)調用。編輯完成後,它現在可以工作。您需要在寫入之前將長度設置爲0,或者在寫入之後將長度設置爲該位置。 – 2009-09-01 17:39:21