Question

Ok, je lis des fichiers dat dans un tableau d'octets. Pour une raison quelconque, les personnes qui génèrent ces fichiers placent environ un demi octet d'octets nuls inutiles à la fin du fichier. Quelqu'un sait-il un moyen rapide de couper ces derniers?

La première idée était de commencer à la fin du tableau et de revenir en arrière jusqu'à ce que je trouve autre chose qu'un null, puis de tout copier jusque-là, mais je me demande s'il n'y a pas de meilleur moyen.

Pour répondre à quelques questions: Etes-vous sûr que les 0 octets sont définitivement dans le fichier, plutôt qu’un bug dans le code de lecture du fichier? Oui, j'en suis certain.

Pouvez-vous vraiment supprimer tous les 0 derniers? Oui.

Peut-il y avoir des 0 dans le reste du fichier? Oui, il peut y avoir d'autres endroits à 0, alors, non, je ne peux pas commencer au début ni au premier 0.

Était-ce utile?

La solution

Compte tenu des questions supplémentaires auxquelles on répond maintenant, il semble que vous fassiez fondamentalement la bonne chose. En particulier, vous devez toucher chaque octet du fichier à partir du dernier 0 pour vérifier qu'il ne contient que des 0.

Maintenant, le fait de tout copier ou non dépend de ce que vous faites ensuite avec les données.

  • Vous pourriez peut-être vous souvenir de l'index et le conserver avec les données ou le nom de fichier.
  • Vous pouvez copier les données dans un nouveau tableau d'octets
  • Si vous voulez "réparer" Pour ce fichier, vous pouvez appeler FileStream.SetLength . pour tronquer le fichier

Le " vous devez lire tous les octets entre le point de troncature et la fin du fichier " est la partie critique cependant.

Autres conseils

Je suis d'accord avec Jon. Le point critique est que vous devez "toucher" chaque octet depuis le dernier jusqu'au premier octet différent de zéro. Quelque chose comme ça:

byte[] foo;
// populate foo
int i = foo.Length - 1;
while(foo[i] == 0)
    --i;
// now foo[i] is the last non-zero byte
byte[] bar = new byte[i+1];
Array.Copy(foo, bar, i+1);

Je suis presque sûr que c'est à peu près aussi efficace que vous pourrez le faire.

@Factor Mystic,

Je pense qu'il existe un moyen le plus court:

var data = new byte[] { 0x01, 0x02, 0x00, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00 };
var new_data = data.TakeWhile((v, index) => data.Skip(index).Any(w => w != 0x00)).ToArray();

Que diriez-vous de cela:

[Test]
public void Test()
{
   var chars = new [] {'a', 'b', '\0', 'c', '\0', '\0'};

   File.WriteAllBytes("test.dat", Encoding.ASCII.GetBytes(chars));

   var content = File.ReadAllText("test.dat");

   Assert.AreEqual(6, content.Length); // includes the null bytes at the end

   content = content.Trim('\0');

   Assert.AreEqual(4, content.Length); // no more null bytes at the end
                                       // but still has the one in the middle
}

En supposant que 0 = null, c’est probablement votre meilleur choix ... en tant que réglage mineur, vous pouvez utiliser Buffer.BlockCopy lorsque vous copiez enfin les données utiles.

testez ceci:

    private byte[] trimByte(byte[] input)
    {
        if (input.Length > 1)
        {
            int byteCounter = input.Length - 1;
            while (input[byteCounter] == 0x00)
            {
                byteCounter--;
            }
            byte[] rv = new byte[(byteCounter + 1)];
            for (int byteCounter1 = 0; byteCounter1 < (byteCounter + 1); byteCounter1++)
            {
                rv[byteCounter1] = input[byteCounter1];
            }
            return rv;
        }

Il y a toujours une réponse LINQ

byte[] data = new byte[] { 0x01, 0x02, 0x00, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00 };
bool data_found = false;
byte[] new_data = data.Reverse().SkipWhile(point =>
{
  if (data_found) return false;
  if (point == 0x00) return true; else { data_found = true; return false; }
}).Reverse().ToArray();

Vous pouvez simplement compter le nombre zéro à la fin du tableau et l'utiliser à la place de .Length lors de l'itération ultérieure du tableau. Vous pouvez encapsuler cela comme bon vous semble. Le point principal est que vous n'avez pas vraiment besoin de le copier dans une nouvelle structure. Si elles sont grandes, cela peut en valoir la peine.

Si, dans le fichier, les octets NULL peuvent être des valeurs valides, savez-vous que le dernier octet du fichier ne peut pas être NULL? Si tel est le cas, il est probablement préférable d’itérer des itérations en arrière et de rechercher la première entrée non nulle. Sinon, il n’ya aucun moyen de savoir où se trouve la fin réelle du fichier.

Si vous en savez plus sur le format des données, par exemple, il ne peut y avoir aucune séquence d'octets nuls supérieurs à deux octets (ou une contrainte similaire). Ensuite, vous pourrez peut-être effectuer une recherche binaire du "point de transition". Cela devrait être beaucoup plus rapide que la recherche linéaire (en supposant que vous puissiez lire tout le fichier).

L'idée de base (en partant de l'hypothèse antérieure selon laquelle il n'y aurait pas d'octet nul consécutif) serait:

var data = (byte array of file data...);
var index = data.length / 2;
var jmpsize = data.length/2;
while(true)
{
    jmpsize /= 2;//integer division
    if( jmpsize == 0) break;
    byte b1 = data[index];
    byte b2 = data[index + 1];
    if(b1 == 0 && b2 == 0) //too close to the end, go left
        index -=jmpsize;
    else
        index += jmpsize;
}

if(index == data.length - 1) return data.length;
byte b1 = data[index];
byte b2 = data[index + 1];
if(b2 == 0)
{
    if(b1 == 0) return index;
    else return index + 1;
}
else return index + 2;

Dans mon cas, l'approche LINQ n'a jamais fini ^))) Il est trop lent pour travailler avec des tableaux d'octets!

Les gars, pourquoi ne pas utiliser la méthode Array.Copy ()?

    /// <summary>
    /// Gets array of bytes from memory stream.
    /// </summary>
    /// <param name="stream">Memory stream.</param>
    public static byte[] GetAllBytes(this MemoryStream stream)
    {
        byte[] result = new byte[stream.Length];
        Array.Copy(stream.GetBuffer(), result, stream.Length);

        return result;
    }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top