3

xmlファイルに変更を加えた後、それらを保存するのに問題があります。私は今日一日中これを理解しようとして過ごしました、そして私はどこにも行きませんでした。

私はこのxmlドキュメントを持っています:

<?xml version=1.0" encoding="utf-8"?>
<content>
      <weapon id="1234" name="blahblah">
         <note info="blah blah" />
      </weapon>
      <weapon id="5678" name="blahblah2">
         <note info="blah blah" />
      </weapon>
</content>

これは私がこれまでに思いついたものであり、正確には機能しません(ファイルの読み取り方法を示すために編集):

FileOpenPicker openPicker = new FileOpenPicker();
openPicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.DocumentsLibrary;
openPicker.FileTypeFilter.Add(".xml");

StorageFile gfile = await openPicker.PickSingleFileAsync()

fileContent = await FileIO.ReadTextAsync(gfile, Windows.Storage.Streams.UnicodeEncoding.Utf8);

Xdocument  xml = XDocument.Parse(fileContent);

xml.Descendants("weapon").Where(c => c.Attribute("id").Value.Equals("5678")).FirstorDefault().Remove();

IRandomAccessStream writeStream = await gfile.OpenAsync(FileAccessMode.ReadWrite);
Stream stream = writeStream.AsStreamForWrite();

xml.Save(stream);

結果のxmlドキュメントは次のようになります。

<?xml version=1.0" encoding="utf-8"?>
<content>
      <weapon id="1234" name="blahblah">
         <note info="blah blah" />
</content>apon>
      <weapon id="5678" name="blahblah2">
         <note info="blah blah" />
      </weapon>
</content>

OpenAsyncにFileAccessMode.ReadWriteNoCopyOnWriteを使用しようとすると、ファイルは0バイトになります。

XDocument.Saveを使用しながら、このファイルを正しく書き込む方法を知っている人はいますか?

4

5 に答える 5

2

System.IO.File.WriteAllTextを使用しないのはなぜですか?

XDocument xml = XDocument.Load(xmlFilePath);

System.IO.File.WriteAllText(xmlFilePath, string.Format(@"<?xml version=""1.0""?>{0}{1}", Environment.NewLine, xml));
于 2014-03-04T11:54:04.000 に答える
1

この問題は、一見したところよりも複雑であることがわかりました。

解決する必要のある問題は次のとおりです。

  • 非同期でファイルに書き込む
  • 効率的に書き込みます。つまり、バッファIOを使用します。
  • ファイル全体を上書きし、必要に応じて既存のファイルをトリミングします
  • 書き込み操作を待機可能にする

多くの実験の後、私が選択した解決策は、XMLをSystem.IO.MemoryStreamに書き込み、そのメモリストリームをストレージファイルにコピーすることです。これには、データの一時的なコピーのためのメモリが必要であることを理解しています。しかし、それは機能し、高速であり(バッファリングされたIO、少数のネイティブWindows呼び出し、3つだけ待機)、正しくトリミングされ、操作の待機は実際に正しく機能します。これは、私が試した他のいくつかの方法には当てはまらないことに注意してください。解決策は次のとおりです。

MemoryStream ms = new MemoryStream()

xml.Save(ms, SaveOptions.DisableFormatting);

await ms.CopyToAsync(gfile);

CopyToAsync拡張メソッド:

using System.IO;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Storage;
using Windows.Storage.Streams;

internal static class Extensions
{
    public static async Task CopyToAsync(this MemoryStream source, StorageFile file)
    {
        using (IRandomAccessStream raStream = await file.OpenAsync(FileAccessMode.ReadWrite))
        {
            using (IOutputStream stream = raStream.GetOutputStreamAt(0))
            {
                await stream.WriteAsync(source.GetWindowsRuntimeBuffer());
                await stream.FlushAsync();
            }

            raStream.Size = raStream.Position;
        }
    }
}
于 2012-05-26T00:16:43.217 に答える
0

こんにちは今日私はXMLファイルを書かなければなりません、そして私が有効なストリームを提供するならばXDocument.Saveがうまくいくなら基本的にそれはうまくいきました。

WinRTは、ファイルシステムへのアクセスが制限されているため、注意が必要な場合があります。

/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{

    public List<DataStructure> DataList { get; set; }

    public MainPage()
    {
        this.InitializeComponent();
        DataList = Enumerable.Range(0, 25).Select(i => new DataStructure() { Id = i, Data = string.Format("Number : {0}", i) }).ToList();
        this.Loaded += MainPage_Loaded;
    }

    async void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        this.Loaded -= MainPage_Loaded;
        //var xmlDocument =
        //    new XDocument(
        //        new XElement("DataList",
        //            DataList.Select(dataItem =>
        //                new XElement("DataItem",
        //                    new XAttribute("id", dataItem.Id), new XAttribute("data", dataItem.Data)))));

        var rootNode = new XElement("DataList");
        var xmlDocument = new XDocument(rootNode);
        foreach (var dataItem in DataList)
        {
            rootNode.Add(new XElement("DataItem",
                            new XAttribute("id", dataItem.Id), new XAttribute("data", dataItem.Data)));
        }

        FileSavePicker savePicker = new FileSavePicker();
        savePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
        // Dropdown of file types the user can save the file as
        savePicker.FileTypeChoices.Add("XML Document", new List<string>() { ".xml" });
        // Default file name if the user does not type one in or select a file to replace
        savePicker.SuggestedFileName = "New Xml Document";

        StorageFile file = await savePicker.PickSaveFileAsync();
        // Process picked file
        if (file != null)
        {
            // Store file for future access
            var fileToken = Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.Add(file);
            var writterStream = await file.OpenStreamForWriteAsync();
            xmlDocument.Save(writterStream);
        }

    }

VS2012(RC)でWinRTのデフォルトプロジェクトを作成します。次に、MainPage.csファイルを前のファイルのように変更しました。このファイルには、データ構造のハードコードされたリストが含まれています。リストに基づいてXDocumentを作成します。最後に、XDocumentを保存するための書き込み可能なストリームを提供するようにユーザーに依頼します。(Isolated Storageから書き込み可能なストリームを取得することもできます)。最後に、適切なStreamを使用してwriteメソッドを呼び出すだけです。

于 2012-10-26T07:22:26.400 に答える
0

私はそれを機能させましたが、あなたのコードの振る舞いについてもっと研究する必要があります。これを試して ...

var local = Windows.Storage.ApplicationData.Current.LocalFolder;
var file = await local.GetFileAsync("test.xml");
var data = await FileIO.ReadTextAsync(file);
var xml = XDocument.Parse(data);

xml.Descendants("weapon").Where(c => c.Attribute("id").Value.Equals("5678")).FirstOrDefault().Remove();

file = await local.CreateFileAsync("test.xml", CreationCollisionOption.ReplaceExisting);
var writeStream = await file.OpenStreamForWriteAsync() as Stream;

xml.Save(writeStream);

writeStream.Flush();

ここで、test.xmlは、元のXMLを含むローカルフォルダー内のファイルです。

于 2012-05-25T00:07:50.920 に答える
0

ディスクにフラッシュするFileStreamに書き込んでいます。

public static async Task SaveXMLAsync(XDocument linqXml, StorageFolder localFolder, string filename)
{
  // Create a storage file
  StorageFile file = await localFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);

  // Write the XML to a File Stream.
  using (FileStream sourceStream = new FileStream(file.Path, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true))
  {
    linqXml.Save(sourceStream);

    // Async flush to disk.
    await sourceStream.FlushAsync();
  };
}
于 2017-06-22T14:44:00.000 に答える