web-dev-qa-db-fra.com

Qu'est-ce qui pourrait amener un fichier XML à être rempli de caractères nuls?

C'est une question délicate. Je suppose que cela nécessitera une connaissance avancée des systèmes de fichiers pour répondre.

J'ai une application WPF, "App1", qui cible .NET Framework 4.0. Il contient un fichier Settings.settings qui génère un fichier standard App1.exe.config dans lequel les paramètres par défaut sont stockés. Lorsque l'utilisateur modifie les paramètres, les modifications vont dans AppData\Roaming\MyCompany\App1\X.X.0.0\user.config. Ceci est tout comportement standard .NET. Cependant, nous avons parfois constaté que le fichier user.config sur la machine d'un client n'était pas ce qu'il était supposé être, ce qui provoquait le blocage de l'application.

Le problème ressemble à ceci: user.config correspond à peu près à la taille qu'il devrait avoir si elle était remplie avec XML, mais au lieu de XML, c'est juste un tas de caractères NUL. C'est le caractère 0 répété encore et encore. Nous n'avons aucune information sur ce qui s'est passé avant cette modification de fichier.

 enter image description here

Nous pouvons résoudre ce problème sur le périphérique d'un client si nous supprimons simplement user.config car Common Language Runtime en générera un nouveau. Ils perdront les modifications apportées aux paramètres, mais ils peuvent être modifiés à nouveau.

Cependant, j'ai rencontré ce problème dans une autre application WPF, "App2", avec un autre fichier XML, info.xml. Cette fois, c'est différent parce que le fichier est généré par mon propre code plutôt que par le CLR. Les thèmes communs sont que les deux sont des applications WPF C #, des fichiers XML et que, dans les deux cas, nous ne pouvons absolument pas reproduire le problème lors de nos tests. Est-ce que cela pourrait avoir quelque chose à voir avec la façon dont les applications C # interagissent avec les fichiers XML ou les fichiers en général?

Non seulement nous ne pouvons pas reproduire le problème dans nos applications actuelles, mais je ne peux même pas reproduire le problème en écrivant un code personnalisé qui génère des erreurs exprès. Je ne parviens pas à trouver une seule erreur de sérialisation XML ou une erreur d'accès au fichier qui aboutit à un fichier rempli de valeurs NULL. Alors que pourrait-il se passer?

App1 accède à user.config en appelant Upgrade() et Save() et en obtenant et en définissant les propriétés. Par exemple:

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

App2 accède à info.xml en sérialisant et en désérialisant le 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();
    }
}

Nous avons rencontré le problème sous Windows 7 et Windows 10. Lors de la recherche du problème, je suis tombé sur cet article dans lequel le même problème XML avait été rencontré sous Windows 8.1: Les fichiers enregistrés ne contiennent parfois que des caractères NUL

Y at-il quelque chose que je pourrais changer dans mon code pour empêcher cela, ou le problème est-il trop profond dans le comportement de .NET?

Il me semble qu'il y a trois possibilités:

  1. Le CLR écrit des caractères nuls dans les fichiers XML.
  2. Le pointeur d'adresse mémoire du fichier est déplacé vers un autre emplacement sans déplacer le contenu du fichier.
  3. Le système de fichiers tente de déplacer le fichier vers une autre adresse mémoire. Le contenu du fichier est déplacé mais le pointeur n'est pas mis à jour.

Je pense que 2 et 3 sont plus susceptibles que 1. C'est pourquoi j'ai dit que cela pourrait nécessiter une connaissance avancée des systèmes de fichiers.

J'apprécierais énormément toute information qui pourrait m'aider à reproduire, corriger ou contourner le problème. Je vous remercie!

10
Kyle Delaney

Il n'y a aucune raison documentée à ce comportement, car cela arrive aux utilisateurs mais personne ne peut dire l'origine de ces conditions étranges. 

Cela peut être un problème de CLR, bien que cela soit très improbable, le CLR n'écrit pas uniquement des caractères nuls et le document XML ne peut pas contenir de caractères nuls s'il n'y a pas de xsi: nil défini pour les nœuds. 

Quoi qu'il en soit, le seul moyen documenté de résoudre ce problème consiste à supprimer le fichier corrompu à l'aide de cette ligne de code:

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

Il restaurera le fichier user.config à l'aide de Properties.Settings.Default.Upgrade(); à nouveau sans valeurs nulles.

2
Barr J

Il est bien connu que cela peut arriver en cas de panne de courant. Cela se produit après une écriture mise en cache qui étend un fichier (il peut s'agir d'un fichier nouveau ou existant) et une panne de courant survient peu de temps après. Dans ce scénario, le fichier a 3 états possibles attendus lorsque l'ordinateur redémarre:

1) Le fichier n'existe pas du tout ou a sa longueur d'origine, comme si l'écriture n'avait jamais eu lieu.

2) Le fichier a la longueur attendue comme si l'écriture s'était produite, mais les données sont des zéros.

3) Le fichier a la longueur attendue et les données correctes écrites.

L'état 2 est ce que vous décrivez. Cela se produit car, lorsque vous effectuez l'écriture en cache, NTFS étend initialement la taille du fichier en conséquence, tout en laissant intacte la VDL (longueur de données valide). Les données au-delà de VDL sont toujours lues en tant que zéros. Les données que vous avez l'intention d'écrire se trouvent dans la mémoire cache du fichier. Il finira par être écrit sur le disque, généralement en quelques secondes, puis VDL sera avancé sur le disque pour refléter les données écrites. Si une panne de courant survient avant l'écriture des données ou avant l'augmentation de VDL, vous vous retrouvez dans l'état 2.

Ceci est assez facile à reproduire, par exemple en copiant un fichier (le moteur de copie utilise des écritures en cache), puis en tirant immédiatement la prise d'alimentation de votre ordinateur.

3
Craig Barkhouse

J'ai eu un problème similaire et j'ai pu retracer mon problème sur un disque dur corrompu. 

Description de mon problème (toutes les informations connexes) :

  • Disque attaché à la carte mère (SATA): 

    • SSD (système) ,

    • 3 * disque dur. 

      L'un des disques durs avait des blocs défectueux et il y avait même des problèmes pour lire la structure du disque (répertoires et listes de fichiers) .

  • Système d'exploitation: Windows 7 x64

  • système de fichiers (sur tous les disques) : NTFS

Lorsque le système a essayé de lire ou d'écrire sur le disque corrompu (demande de l'utilisateur, analyse automatique ou toute autre raison) et que la tentative a échoué, toutes les opérations d'écriture (sur d'autres disques) étaient incorrectes. Les fichiers créés sur le disque système (principalement des fichiers de configuration créés par d’autres applications) ont été écrits et sont valides (probablement parce que les fichiers ont été encaissés dans la RAM) lors de la vérification directe du contenu du fichier.

Malheureusement, après un redémarrage, tous les fichiers (écrits après un accès en écriture/en lecture ayant échoué sur le lecteur corrompu) avaient la taille correcte, mais le contenu des fichiers était 'octet nul' (exactement comme dans votre cas ) .

Essayez d’exclure les problèmes liés au matériel. Vous pouvez essayer de cocher 'copier' le fichier (après modification) sur une autre machine (télécharger sur le Web/ftp) . Ou essayez de sauvegarder un contenu spécifique dans un fichier fixe. Lorsque le fichier de contrôle sur différent est correct ou lorsque le fichier de contenu fixe est "vide", la raison est probablement sur l'ordinateur local. Essayez de modifier les composants matériels ou réinstallez le système.

3
Julo

J'ai rencontré un problème similaire, mais c'était sur un serveur. Le serveur a redémarré alors qu'un programme écrivait dans un fichier, ce qui lui a valu de contenir tous les caractères nuls et de devenir inutilisable pour le programme qui l'écrit ou le lisait. 

Donc, le fichier ressemblait à ceci:  enter image description here

Les journaux ont montré que le serveur avait redémarré:  enter image description here

Le fichier corrompu indiquait que sa dernière mise à jour avait été effectuée au moment du redémarrage:  enter image description here

2
Beastwood

J'ai le même problème, il y a un caractère "NUL" supplémentaire à la fin du fichier xml sérialisé:  enter image description here

J'utilise XMLWriter comme ceci:

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
Fatemeh Ramezani