132 votes

Comment convertir un objet en tableau d'octets en C# ?

J'ai une collection d'objets que je dois écrire dans un fichier binaire.

J'ai besoin que les octets du fichier soient compacts, donc je ne peux pas utiliser BinaryFormatter . BinaryFormatter ajoute toutes sortes d'informations pour les besoins de la désérialisation.

Si j'essaie

byte[] myBytes = (byte[]) myObject 

J'obtiens une exception d'exécution.

J'ai besoin que ce soit rapide, donc je préfère ne pas avoir à copier des tableaux d'octets. Je voudrais juste que le cast byte[] myBytes = (byte[]) myObject au travail !

OK, juste pour être clair, je ne peux pas avoir cualquier dans le fichier de sortie. Seulement les octets de l'objet. Emballé d'objet à objet. D'après les réponses reçues, il semble que j'écrirai des Buffer.BlockCopy code. Peut-être en utilisant un code peu sûr.

221voto

Crystalonics Points 251

Pour convertir un objet en tableau d'octets :

// Convert an object to a byte array
public static byte[] ObjectToByteArray(Object obj)
{
    BinaryFormatter bf = new BinaryFormatter();
    using (var ms = new MemoryStream())
    {
        bf.Serialize(ms, obj);
        return ms.ToArray();
    }
}

Il vous suffit de copier cette fonction dans votre code et de lui envoyer l'objet à convertir en tableau d'octets. Si vous devez à nouveau convertir le tableau d'octets en objet, vous pouvez utiliser la fonction ci-dessous :

// Convert a byte array to an Object
public static Object ByteArrayToObject(byte[] arrBytes)
{
    using (var memStream = new MemoryStream())
    {
        var binForm = new BinaryFormatter();
        memStream.Write(arrBytes, 0, arrBytes.Length);
        memStream.Seek(0, SeekOrigin.Begin);
        var obj = binForm.Deserialize(memStream);
        return obj;
    }
}

Vous pouvez utiliser ces fonctions avec des classes personnalisées. Il vous suffit d'ajouter l'élément [Serializable] dans votre classe pour permettre la sérialisation

51voto

Guffa Points 308133

Si vous souhaitez que les données sérialisées soient vraiment compactes, vous pouvez écrire vous-même des méthodes de sérialisation. De cette façon, vous aurez un minimum de frais généraux.

Exemple :

public class MyClass {

   public int Id { get; set; }
   public string Name { get; set; }

   public byte[] Serialize() {
      using (MemoryStream m = new MemoryStream()) {
         using (BinaryWriter writer = new BinaryWriter(m)) {
            writer.Write(Id);
            writer.Write(Name);
         }
         return m.ToArray();
      }
   }

   public static MyClass Desserialize(byte[] data) {
      MyClass result = new MyClass();
      using (MemoryStream m = new MemoryStream(data)) {
         using (BinaryReader reader = new BinaryReader(m)) {
            result.Id = reader.ReadInt32();
            result.Name = reader.ReadString();
         }
      }
      return result;
   }

}

32voto

Jon Skeet Points 692016

Eh bien, une distribution de myObject à byte[] ne fonctionnera jamais à moins d'avoir une conversion explicite ou si myObject es a byte[] . Vous avez besoin d'un cadre de sérialisation de certains genre. Il en existe de nombreux, notamment Tampons de protocole qui m'est chère. C'est un endroit assez "maigre" en termes d'espace et de temps.

Vous constaterez que presque tous les cadres de sérialisation ont des restrictions importantes sur ce que vous pouvez sérialiser, cependant - les tampons de protocole plus que d'autres, en raison du fait qu'ils sont multiplateformes.

Si vous pouvez nous donner plus d'informations, nous pourrons vous aider davantage - mais ce ne sera jamais aussi simple que de faire un casting...

EDIT : Juste pour répondre à cela :

J'ai besoin que mon fichier binaire contienne les éléments suivants les octets de l'objet. Seulement les octets, pas de métadonnées. Emballé d'objet à objet. Je vais donc implémenter une sérialisation personnalisée.

N'oubliez pas que les octets contenus dans vos objets sont souvent des références... vous devrez donc déterminer ce qu'il faut en faire.

Je pense que vous découvrirez que la conception et la mise en œuvre de votre propre cadre de sérialisation personnalisé est plus difficile que vous ne l'imaginez.

Je recommanderais personnellement que si vous n'avez besoin de faire cela que pour quelques types spécifiques, vous ne vous embêtez pas à essayer de mettre au point un cadre de sérialisation général. Il suffit d'implémenter une méthode d'instance et une méthode statique dans tous les types dont vous avez besoin :

public void WriteTo(Stream stream)
public static WhateverType ReadFrom(Stream stream)

Une chose à garder à l'esprit : tout devient plus délicat si l'on a recours à l'héritage. Sans héritage, si vous savez avec quel type vous commencez, vous n'avez pas besoin d'inclure d'informations sur le type. Bien sûr, il y a aussi la question du versionnage - devez-vous vous préoccuper de la compatibilité ascendante et descendante avec les différentes versions de vos types ?

23voto

jhilden Points 759

J'ai pris les réponses de Crystalonics et les ai transformées en méthodes d'extension. J'espère que quelqu'un d'autre les trouvera utiles :

public static byte[] SerializeToByteArray(this object obj)
{
    if (obj == null)
    {
        return null;
    }
    var bf = new BinaryFormatter();
    using (var ms = new MemoryStream())
    {
        bf.Serialize(ms, obj);
        return ms.ToArray();
    }
}

public static T Deserialize<T>(this byte[] byteArray) where T : class
{
    if (byteArray == null)
    {
        return null;
    }
    using (var memStream = new MemoryStream())
    {
        var binForm = new BinaryFormatter();
        memStream.Write(byteArray, 0, byteArray.Length);
        memStream.Seek(0, SeekOrigin.Begin);
        var obj = (T)binForm.Deserialize(memStream);
        return obj;
    }
}

22voto

MiKey Points 43

L'utilisation du formateur binaire est désormais considérée comme peu sûre. voir --> Docs Microsoft

Il suffit d'utiliser System.Text.Json :

Pour sérialiser en octets :

JsonSerializer.SerializeToUtf8Bytes(obj) ;

Pour désérialiser vers votre type :

JsonSerializer.Deserialize(byteArray) ;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X