it-swarm.com.de

Was kann dazu führen, dass eine XML-Datei mit Nullzeichen gefüllt wird?

Das ist eine knifflige Frage. Ich vermute, dass es einige fortgeschrittene Kenntnisse der Dateisysteme erfordert, um zu antworten.

Ich habe eine WPF-Anwendung, "App1", die auf .NET Framework 4.0 abzielt. Es verfügt über eine Settings.settings-Datei, die eine App1.exe.config-Standarddatei generiert, in der Standardeinstellungen gespeichert werden. Wenn der Benutzer Einstellungen ändert, werden die Änderungen in AppData\Roaming\MyCompany\App1\X.X.0.0\user.config gespeichert. Dies ist das Standardverhalten von .NET. Gelegentlich haben wir jedoch festgestellt, dass die user.config-Datei auf dem Computer eines Kunden nicht dem entspricht, was zu einem Absturz der Anwendung führen kann.

Das Problem sieht folgendermaßen aus: user.config entspricht in etwa der Größe, die es haben sollte, wenn es mit XML gefüllt wäre, aber anstelle von XML sind es nur ein paar NUL-Zeichen. Es ist Zeichen 0 immer und immer wieder wiederholt. Wir haben keine Informationen darüber, was vor dieser Dateiänderung passiert ist.

 enter image description here

Wir können dieses Problem auf dem Gerät eines Kunden beheben, indem wir nur user.config löschen, da die Common Language Runtime nur einen neuen generiert. Sie verlieren die Änderungen, die sie an den Einstellungen vorgenommen haben, aber die Änderungen können erneut vorgenommen werden.

Ich habe dieses Problem jedoch in einer anderen WPF-Anwendung, "App2", mit einer anderen XML-Datei, info.xml, festgestellt. Diesmal ist es anders, weil die Datei nicht von der CLR, sondern von meinem eigenen Code generiert wird. Die gemeinsamen Themen sind, dass beide C # WPF-Anwendungen sind, beide XML-Dateien, und in beiden Fällen können wir das Problem in unseren Tests nicht vollständig reproduzieren. Könnte dies etwas mit der Art und Weise zu tun haben, wie C # -Anwendungen mit XML-Dateien oder Dateien im Allgemeinen interagieren?

Wir können das Problem nicht nur in unseren aktuellen Anwendungen nicht reproduzieren, sondern ich kann es auch nicht reproduzieren, indem ich benutzerdefinierten Code schreibe, der absichtlich Fehler generiert. Ich kann keinen einzelnen XML-Serialisierungsfehler oder Dateizugriffsfehler finden, der zu einer Datei führt, die mit Nullen gefüllt ist. Was könnte also los sein?

App1 greift auf user.config zu, indem Upgrade() und Save() aufgerufen und die Eigenschaften abgerufen und festgelegt werden. Zum Beispiel:

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

App2 greift auf info.xml zu, indem das XML serialisiert und deserialisiert wird:

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

Wir haben das Problem sowohl unter Windows 7 als auch unter Windows 10 festgestellt. Bei der Untersuchung des Problems bin ich auf diesen Beitrag gestoßen, in dem dasselbe XML-Problem in Windows 8.1 aufgetreten ist: Gespeicherte Dateien enthalten manchmal nur NUL-Zeichen

Gibt es etwas, das ich in meinem Code ändern könnte, um dies zu verhindern, oder liegt das Problem zu tief im Verhalten von .NET?

Es scheint mir, dass es drei Möglichkeiten gibt:

  1. Die CLR schreibt Nullzeichen in die XML-Dateien.
  2. Der Speicheradressenzeiger der Datei wechselt an einen anderen Speicherort, ohne den Dateiinhalt zu verschieben.
  3. Das Dateisystem versucht, die Datei in eine andere Speicheradresse zu verschieben, und der Dateiinhalt wird verschoben, aber der Zeiger wird nicht aktualisiert.

Ich glaube, 2 und 3 sind wahrscheinlicher als 1. Aus diesem Grund habe ich gesagt, dass dafür möglicherweise fortgeschrittene Kenntnisse der Dateisysteme erforderlich sind.

Ich würde mich sehr über Informationen freuen, die mir helfen könnten, das Problem zu reproduzieren, zu beheben oder zu umgehen. Vielen Dank!

10
Kyle Delaney

Es gibt keinen dokumentierten Grund für dieses Verhalten, da dies den Benutzern passiert, aber niemand kann den Ursprung dieser ungeraden Bedingungen erkennen. 

Es kann ein CLR-Problem sein, obwohl dies sehr unwahrscheinlich ist. Die CLR schreibt nicht nur Nullzeichen und das XML-Dokument darf keine Nullzeichen enthalten, wenn für die Knoten kein xsi: nil definiert ist. 

Die einzige dokumentierte Möglichkeit, dieses Problem zu beheben, besteht darin, die beschädigte Datei mithilfe der folgenden Codezeile zu löschen:

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

Die user.config wird mit der Properties.Settings.Default.Upgrade(); Ohne Nullwerte wieder hergestellt.

2
Barr J

Es ist bekannt, dass dies bei Stromausfall passieren kann. Dies geschieht nach einem zwischengespeicherten Schreibvorgang, durch den eine Datei erweitert wird (es kann sich um eine neue oder vorhandene Datei handeln), und kurz danach tritt ein Stromausfall auf. In diesem Szenario hat die Datei drei mögliche Zustände, wenn der Computer wieder hochgefahren wird:

1) Die Datei existiert überhaupt nicht oder hat ihre ursprüngliche Länge, als ob der Schreibvorgang niemals stattgefunden hätte.

2) Die Datei hat die erwartete Länge, als ob der Schreibvorgang erfolgt wäre, die Daten sind jedoch Nullen.

3) Die Datei hat die erwartete Länge und die korrekten Daten, die geschrieben wurden.

Zustand 2 ist das, was Sie beschreiben. Es tritt auf, weil NTFS beim Zwischenspeichern zunächst die Dateigröße entsprechend vergrößert, VDL (gültige Datenlänge) jedoch nicht ändert. Daten jenseits von VDL werden immer als Nullen zurückgelesen. Die Daten, die Sie schreiben wollten, befinden sich im Dateicache. Es wird in der Regel innerhalb weniger Sekunden auf die Festplatte geschrieben, und danach wird VDL auf der Festplatte vorgerückt, um die geschriebenen Daten wiederzugeben. Wenn es zu einem Stromausfall kommt, bevor die Daten geschrieben werden oder bevor VDL erhöht wird, landen Sie im Zustand 2.

Dies ist ziemlich einfach zu reproduzieren, z. B. durch Kopieren einer Datei (das Kopiermodul verwendet zwischengespeicherte Schreibvorgänge) und anschließend sofort den Netzstecker an Ihrem Computer.

3
Craig Barkhouse

Ich hatte ein ähnliches Problem und konnte mein Problem auf eine beschädigte Festplatte zurückführen. 

Beschreibung meines Problems (alle zugehörigen Informationen):

  • An das Mainboard angeschlossene Festplatte (SATA): 

    • SSD (System),

    • 3 * HDD. 

      Eine der Festplatten hatte fehlerhafte Blöcke und es gab sogar Probleme beim Lesen der Festplattenstruktur (Verzeichnisse und Dateiliste).

  • Betriebssystem: Windows 7 x64

  • dateisystem (auf allen Festplatten): NTFS

Wenn das System versuchte, auf die beschädigte Festplatte zu lesen oder zu schreiben (Benutzeranfrage oder automatischer Scan oder aus einem anderen Grund) und der Versuch fehlgeschlagen ist, waren alle Schreibvorgänge (auf anderen Festplatten) falsch. Die auf der Systemfestplatte erstellten Dateien (meist Konfigurationsdateien einer anderen Anwendung) wurden geschrieben und waren gültig (wahrscheinlich weil die Dateien im RAM eingelesen wurden), wenn der Dateiinhalt direkt geprüft wurde.

Leider hatten nach einem Neustart alle Dateien (geschrieben nach dem fehlgeschlagenen Schreib-/Lesezugriff auf beschädigtem Laufwerk) die richtige Größe, aber der Inhalt der Dateien war 'null Byte' (genau wie in Ihrem Fall) ).

Versuchen Sie, Hardwareprobleme auszuschließen. Sie können versuchen, die Datei nach einer Änderung auf eine andere Maschine zu kopieren (Hochladen in Web/FTP). Oder versuchen Sie, bestimmte Inhalte in einer festen Datei zu speichern. Wenn die zu prüfende Datei unterschiedlich ist oder die feste Inhaltsdatei 'leer' ist, liegt der Grund wahrscheinlich auf der lokalen Maschine. Ändern Sie die HW-Komponenten oder installieren Sie das System erneut.

3
Julo

Ich bin auf ein ähnliches Problem gestoßen, aber es war auf einem Server. Der Server wurde neu gestartet, während ein Programm in eine Datei schrieb, die dazu führte, dass die Datei alle Nullzeichen enthielt und für das Programm unbrauchbar wurde, das daraus schreibt/liest. 

Die Datei sah also so aus:  enter image description here

Die Protokolle zeigten, dass der Server neu gestartet wurde:  enter image description here

Die beschädigte Datei zeigte, dass sie zum Zeitpunkt des Neustarts zuletzt aktualisiert wurde:  enter image description here

2
Beastwood

Ich habe das gleiche Problem, es gibt ein zusätzliches "NUL" -Zeichen am Ende der serialisierten XML-Datei:  enter image description here

Ich verwende XMLWriter so:

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