Исключительно открыть / изменить файл XML? - PullRequest
3 голосов
/ 01 сентября 2009

Мне нужно открыть только 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>

Я знаю, что могу открыть файл и использовать методы File, чтобы построчно анализировать его и вносить изменения ... но я надеялся на что-то более элегантное. Первый метод - загрузка файла с использованием ReadXml - делает изменение файла просто отлично, но у него, похоже, нет никаких вариантов для открытия файла исключительно. Я что-то упустил?

Ответы [ 2 ]

6 голосов
/ 01 сентября 2009

Вы можете сделать это с потоком, но вам нужно сбросить поток до записи:

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);
}
5 голосов
/ 01 сентября 2009

В вашем потоке вам нужно сбросить заголовок потока на начало файла И стереть существующее содержимое, чтобы перезаписать существующие данные в случае, если ваш замещающий текст короче исходного содержимого. Попробуйте разместить это до ds.writeXml:

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

Первая строка перемещает голову, вторая усекает файл, поэтому если текст, которым вы заменяете текст, короче исходного текста, в конце не будет лишних символов.

Обратите внимание, что, как указывает Рид Копси, лучше сначала выполнить запись, а затем установить длину для элемента Position потока, поскольку это не повлияет на случай, если замещающий текст будет такой же длины или длиннее замененного текста, что может быть несколько более эффективным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...