web-dev-qa-db-ja.com

XMLファイルがnull文字で埋められる原因は何ですか?

これはトリッキーな質問です。回答するには、ファイルシステムに関する高度な知識が必要になると思います。

.NET Framework 4.0を対象とするWPFアプリケーション「App1」を持っています。デフォルトの設定が保存されている標準の_Settings.settings_ファイルを生成する_App1.exe.config_ファイルがあります。ユーザーが設定を変更すると、その変更は_AppData\Roaming\MyCompany\App1\X.X.0.0\user.config_に入ります。これはすべて標準の.NET動作です。ただし、場合によっては、お客様のマシンの_user.config_ファイルが想定されたものと異なるため、アプリケーションがクラッシュすることがあります。

問題は次のようになります。_user.config_は、XMLで埋められた場合のサイズとほぼ同じですが、XMLではなくNUL文字の集まりです。それは何度も何度も繰り返される文字0です。このファイルの変更に至るまでに何が起こったかについての情報はありません。

enter image description here

共通言語ランタイムは新しいものを生成するだけなので、_user.config_を削除するだけで、お客様のデバイスでこの問題を修正できます。設定に加えた変更は失われますが、変更は再度行うことができます。

ただし、別のXMLファイル_info.xml_を使用する別のWPFアプリケーション「App2」でこの問題が発生しました。今回は、ファイルがCLRではなく自分のコードによって生成されているため、これは異なります。共通のテーマは、どちらもC#WPFアプリケーションであり、どちらもXMLファイルであり、どちらの場合もテストで問題を完全に再現することはできません。これは、C#アプリケーションがXMLファイルまたは一般的なファイルとやり取りする方法と関係があるのでしょうか?

現在のアプリケーションで問題を再現できないだけでなく、わざとエラーを生成するカスタムコードを記述して問題を再現することもできません。 nullで埋められたファイルが発生する単一のXMLシリアル化エラーまたはファイルアクセスエラーが見つかりません。何が起こっているのでしょうか?

App1は、Upgrade()およびSave()を呼び出し、プロパティを取得および設定することにより、_user.config_にアクセスします。例えば:

_if (Settings.Default.UpgradeRequired)
{
    Settings.Default.Upgrade();
    Settings.Default.UpgradeRequired = false;
    Settings.Default.Save();
}
_

App2は、XMLをシリアル化および逆シリアル化することによって_info.xml_にアクセスします。

_public Info Deserialize(string xmlFile)
{
    if (File.Exists(xmlFile) == false)
    {
        return null;
    }

    XmlSerializer xmlReadSerializer = new XmlSerializer(typeof(Info));

    Info overview = null;

    using (StreamReader file = new StreamReader(xmlFile))
    {
        overview = (Info)xmlReadSerializer.Deserialize(file);
        file.Close();
    }

    return overview;
}

public void Serialize(Info infoObject, string fileName)
{
    XmlSerializer writer = new XmlSerializer(typeof(Info));

    using (StreamWriter fileWrite = new StreamWriter(fileName))
    {
        writer.Serialize(fileWrite, infoObject);
        fileWrite.Close();
    }
}
_

Windows 7とWindows 10の両方で問題が発生しました。問題を調査したところ、Windows 8.1で同じXMLの問題が発生したこの投稿に遭遇しました: 保存されたファイルにNULのみが含まれる場合-文字

これを防ぐためにコードで変更できるものはありますか、それとも.NETの動作内の問題が深すぎますか?

3つの可能性があるように私には思えます:

  1. CLRがXMLファイルにnull文字を書き込んでいます。
  2. ファイルのメモリアドレスポインタは、ファイルの内容を移動せずに別の場所に切り替えられます。
  3. ファイルシステムはファイルを別のメモリアドレスに移動しようとしますが、ファイルの内容は移動されますが、ポインタは更新されません。

2と3は1よりも可能性が高いように感じます。そのため、ファイルシステムの高度な知識が必要になる可能性があると述べました。

問題の再現、修正、または回避に役立つ可能性のある情報をいただければ幸いです。ありがとうございました!

15
Kyle Delaney

これはユーザーに起こっているので、この動作の文書化された理由はありませんが、この奇妙な条件の起源を誰も知ることができません。

これはCLRの問題である可能性がありますが、これは非常にまれですが、ノードに xsi:nil が定義されていない場合、CLRはnull文字を書き込むだけでなく、XMLドキュメントにnull文字を含めることはできません。

とにかく、これを修正する唯一の文書化された方法は、次のコード行を使用して破損したファイルを削除することです。

_try
{
     ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
}
catch (ConfigurationErrorsException ex)
{
    string filename = ex.Filename;
    _logger.Error(ex, "Cannot open config file");

    if (File.Exists(filename) == true)
    {
        _logger.Error("Config file {0} content:\n{1}", filename, File.ReadAllText(filename));
        File.Delete(filename);
        _logger.Error("Config file deleted");
        Properties.Settings.Default.Upgrade();
        // Properties.Settings.Default.Reload();
        // you could optionally restart the app instead
    }
    else
    {
        _logger.Error("Config file {0} does not exist", filename);
    }
}
_

Null値なしでProperties.Settings.Default.Upgrade();を使用してuser.configを復元します。

2
Barr J

これは、停電が発生した場合に発生する可能性があることはよく知られています。これは、ファイルを拡張するキャッシュされた書き込み(新しいファイルでも既存のファイルでもかまいません)の後に発生し、その後すぐに電源喪失が発生します。このシナリオでは、マシンが復旧したときに、ファイルには3つの予想される状態があります。

1)ファイルがまったく存在しないか、書き込みが行われなかったかのように、元の長さが残っている。

2)ファイルは、書き込みが行われたかのように予想される長さですが、データはゼロです。

3)ファイルには、予想された長さと書き込まれた正しいデータが含まれています。

状態2は、あなたが説明しているものです。これは、キャッシュされた書き込みを行うと、NTFSは最初はそれに応じてファイルサイズを拡張するだけですが、VDL(有効なデータ長)はそのままにします。 VDLを超えるデータは常にゼロとして読み戻されます。書き込むつもりのデータは、ファイルキャッシュのメモリにあります。最終的には、通常は数秒以内にディスクに書き込まれ、それに続いてVDLがディスク上に進み、書き込まれたデータを反映します。データが書き込まれる前、またはVDLが増加する前に停電が発生した場合、状態2になります。

これは、たとえばファイルをコピーして(コピーエンジンがキャッシュされた書き込みを使用する)、すぐにコンピューターの電源プラグを抜くなど、かなり簡単に再現できます。

4
Craig Barkhouse

同様の問題が発生し、HDDの破損を追跡できました。

私の問題の説明((すべての関連情報)

  • メインボードに接続されたディスク(SATA):

    • SSD (システム)

    • 3 * HDD。

      HDDの1つに不良ブロックがあり、ディスク構造((ディレクトリとファイルリスト))の読み取りに問題がありました。

  • 操作システム:Windows 7 x64

  • ファイルシステム(すべてのディスク上):NTFS

システムが破損したディスクの読み取りまたは書き込みを試みたとき(ユーザー要求または自動スキャンまたはその他の理由)試行が失敗した場合、すべての書き込み操作(他のディスクへ)間違いでした。システムディスク上に作成されたファイル(ほとんどの場合、別のアプリケーションによる構成ファイル)は書き込まれ、有効でした(ファイルがRAMにキャッシュされたためと思われます)ファイルの内容を直接チェックしました。

残念ながら、再起動後、すべてのファイル(破損したドライブでの書き込み/読み取りアクセスの失敗後に書き込まれます)は正しいサイズでしたが、ファイルの内容は「ゼロバイト」でした(あなたの場合とまったく同じです)

ハードウェア関連の問題を除外します。別のマシンに(変更後の)ファイルの 'コピー'を確認してみてください(web/ftpにアップロード)。または、特定のコンテンツを固定ファイルに保存してみてください。別のチェックファイルが正しい場合、またはフィックスコンテンツファイルが「空」になる場合、その理由はおそらくローカルマシンにあります。 HWコンポーネントを変更するか、システムを再インストールしてください。

3
Julo

私は同様の問題に遭遇しましたが、それはサーバー上にありました。プログラムがファイルに書き込みを行っているときにサーバーが再起動したため、ファイルにすべてのnull文字が含まれ、プログラムがファイルを読み書きできないようになりました。

したがって、ファイルは次のようになります。 enter image description here

ログはサーバーが再起動したことを示しました: enter image description here

破損したファイルは、再起動時に最後に更新されたことを示していました: enter image description here

2
Beastwood

同じ問題があります。シリアル化されたxmlファイルの最後に余分な「NUL」文字があります。 enter image description here

私はこのようなXMLWriterを使用しています:

using (var stringWriter = new Utf8StringWriter())
        {
            using (var xmlWriter = XmlWriter.Create(stringWriter, new XmlWriterSettings { Indent = true, IndentChars = "\t", NewLineChars = "\r\n", NewLineHandling = NewLineHandling.Replace }))
            {                    
                xmlSerializer.Serialize(xmlWriter, data, nameSpaces);
                xml =  stringWriter.ToString();
                var xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(xml);
                if (removeEmptyNodes)
                {
                    RemoveEmptyNodes(xmlDocument);
                }
                xml = xmlDocument.InnerXml;
            }
        }
1