¿Cómo guardar / restaurar un objeto serializable a / desde un archivo?

94

Tengo una lista de objetos y necesito guardarla en algún lugar de mi computadora. He leído algunos foros y sé que el objeto tiene que ser Serializable. Pero sería bueno si pudiera darme un ejemplo. Por ejemplo, si tengo lo siguiente:

[Serializable]
public class SomeClass
{
     public string someProperty { get; set; }
}

SomeClass object1 = new SomeClass { someProperty = "someString" };

Pero, ¿cómo puedo almacenar object1en algún lugar de mi computadora y luego recuperar?

Tono Nam
fuente
3
Aquí hay un tutorial que muestra cómo serializar en un archivo switchonthecode.com/tutorials/…
Brook

Respuestas:

142

Puede utilizar lo siguiente:

    /// <summary>
    /// Serializes an object.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="serializableObject"></param>
    /// <param name="fileName"></param>
    public void SerializeObject<T>(T serializableObject, string fileName)
    {
        if (serializableObject == null) { return; }

        try
        {
            XmlDocument xmlDocument = new XmlDocument();
            XmlSerializer serializer = new XmlSerializer(serializableObject.GetType());
            using (MemoryStream stream = new MemoryStream())
            {
                serializer.Serialize(stream, serializableObject);
                stream.Position = 0;
                xmlDocument.Load(stream);
                xmlDocument.Save(fileName);
            }
        }
        catch (Exception ex)
        {
            //Log exception here
        }
    }


    /// <summary>
    /// Deserializes an xml file into an object list
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="fileName"></param>
    /// <returns></returns>
    public T DeSerializeObject<T>(string fileName)
    {
        if (string.IsNullOrEmpty(fileName)) { return default(T); }

        T objectOut = default(T);

        try
        {
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load(fileName);
            string xmlString = xmlDocument.OuterXml;

            using (StringReader read = new StringReader(xmlString))
            {
                Type outType = typeof(T);

                XmlSerializer serializer = new XmlSerializer(outType);
                using (XmlReader reader = new XmlTextReader(read))
                {
                    objectOut = (T)serializer.Deserialize(reader);
                }
            }
        }
        catch (Exception ex)
        {
            //Log exception here
        }

        return objectOut;
    }
Alex Méndez
fuente
1
¡Agradable! Aunque string attributeXml = string.Empty;en DeSerializeObjectnunca se usa;)
Jimbo
3
No es necesario llamar al método de cierre en un lector dentro de su bloque de uso. Dispose () es implícito y tendrá lugar incluso si se genera una excepción dentro del bloque antes del cierre explícito (). Bloque de código muy útil.
S. Brentson
2
Cómo guardar una lista de objetos usando esta función La he usado pero está guardando solo el último objeto en mi lista
Decoder94
1
Este método no guardará campos internos o privados, puede usar esto: github.com/mrbm2007/ObjectSaver
mrbm
152

Acabo de escribir una publicación de blog sobre cómo guardar los datos de un objeto en Binary, XML o Json . Tiene razón en que debe decorar sus clases con el atributo [Serializable], pero solo si está utilizando serialización binaria. Es posible que prefiera utilizar la serialización XML o Json. Aquí están las funciones para hacerlo en los distintos formatos. Consulte la publicación de mi blog para obtener más detalles.

Binario

/// <summary>
/// Writes the given object instance to a binary file.
/// <para>Object type (and all child types) must be decorated with the [Serializable] attribute.</para>
/// <para>To prevent a variable from being serialized, decorate it with the [NonSerialized] attribute; cannot be applied to properties.</para>
/// </summary>
/// <typeparam name="T">The type of object being written to the binary file.</typeparam>
/// <param name="filePath">The file path to write the object instance to.</param>
/// <param name="objectToWrite">The object instance to write to the binary file.</param>
/// <param name="append">If false the file will be overwritten if it already exists. If true the contents will be appended to the file.</param>
public static void WriteToBinaryFile<T>(string filePath, T objectToWrite, bool append = false)
{
    using (Stream stream = File.Open(filePath, append ? FileMode.Append : FileMode.Create))
    {
        var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
        binaryFormatter.Serialize(stream, objectToWrite);
    }
}

/// <summary>
/// Reads an object instance from a binary file.
/// </summary>
/// <typeparam name="T">The type of object to read from the binary file.</typeparam>
/// <param name="filePath">The file path to read the object instance from.</param>
/// <returns>Returns a new instance of the object read from the binary file.</returns>
public static T ReadFromBinaryFile<T>(string filePath)
{
    using (Stream stream = File.Open(filePath, FileMode.Open))
    {
        var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
        return (T)binaryFormatter.Deserialize(stream);
    }
}

XML

Requiere que el ensamblado System.Xml se incluya en su proyecto.

/// <summary>
/// Writes the given object instance to an XML file.
/// <para>Only Public properties and variables will be written to the file. These can be any type though, even other classes.</para>
/// <para>If there are public properties/variables that you do not want written to the file, decorate them with the [XmlIgnore] attribute.</para>
/// <para>Object type must have a parameterless constructor.</para>
/// </summary>
/// <typeparam name="T">The type of object being written to the file.</typeparam>
/// <param name="filePath">The file path to write the object instance to.</param>
/// <param name="objectToWrite">The object instance to write to the file.</param>
/// <param name="append">If false the file will be overwritten if it already exists. If true the contents will be appended to the file.</param>
public static void WriteToXmlFile<T>(string filePath, T objectToWrite, bool append = false) where T : new()
{
    TextWriter writer = null;
    try
    {
        var serializer = new XmlSerializer(typeof(T));
        writer = new StreamWriter(filePath, append);
        serializer.Serialize(writer, objectToWrite);
    }
    finally
    {
        if (writer != null)
            writer.Close();
    }
}

/// <summary>
/// Reads an object instance from an XML file.
/// <para>Object type must have a parameterless constructor.</para>
/// </summary>
/// <typeparam name="T">The type of object to read from the file.</typeparam>
/// <param name="filePath">The file path to read the object instance from.</param>
/// <returns>Returns a new instance of the object read from the XML file.</returns>
public static T ReadFromXmlFile<T>(string filePath) where T : new()
{
    TextReader reader = null;
    try
    {
        var serializer = new XmlSerializer(typeof(T));
        reader = new StreamReader(filePath);
        return (T)serializer.Deserialize(reader);
    }
    finally
    {
        if (reader != null)
            reader.Close();
    }
}

Json

Debe incluir una referencia al ensamblado Newtonsoft.Json, que se puede obtener del paquete Json.NET NuGet .

/// <summary>
/// Writes the given object instance to a Json file.
/// <para>Object type must have a parameterless constructor.</para>
/// <para>Only Public properties and variables will be written to the file. These can be any type though, even other classes.</para>
/// <para>If there are public properties/variables that you do not want written to the file, decorate them with the [JsonIgnore] attribute.</para>
/// </summary>
/// <typeparam name="T">The type of object being written to the file.</typeparam>
/// <param name="filePath">The file path to write the object instance to.</param>
/// <param name="objectToWrite">The object instance to write to the file.</param>
/// <param name="append">If false the file will be overwritten if it already exists. If true the contents will be appended to the file.</param>
public static void WriteToJsonFile<T>(string filePath, T objectToWrite, bool append = false) where T : new()
{
    TextWriter writer = null;
    try
    {
        var contentsToWriteToFile = JsonConvert.SerializeObject(objectToWrite);
        writer = new StreamWriter(filePath, append);
        writer.Write(contentsToWriteToFile);
    }
    finally
    {
        if (writer != null)
            writer.Close();
    }
}

/// <summary>
/// Reads an object instance from an Json file.
/// <para>Object type must have a parameterless constructor.</para>
/// </summary>
/// <typeparam name="T">The type of object to read from the file.</typeparam>
/// <param name="filePath">The file path to read the object instance from.</param>
/// <returns>Returns a new instance of the object read from the Json file.</returns>
public static T ReadFromJsonFile<T>(string filePath) where T : new()
{
    TextReader reader = null;
    try
    {
        reader = new StreamReader(filePath);
        var fileContents = reader.ReadToEnd();
        return JsonConvert.DeserializeObject<T>(fileContents);
    }
    finally
    {
        if (reader != null)
            reader.Close();
    }
}

Ejemplo

// Write the contents of the variable someClass to a file.
WriteToBinaryFile<SomeClass>("C:\someClass.txt", object1);

// Read the file contents back into a variable.
SomeClass object1= ReadFromBinaryFile<SomeClass>("C:\someClass.txt");
perro mortal
fuente
2
Me gusta su código de serialización binario. Pero en WriteToBinaryFile, ¿por qué querrías agregar al archivo? Parece que querrá crear un nuevo archivo en todos los casos. De lo contrario, habría mucha información adicional sobre la deserialización.
inalámbrico público
1
@publicwireless Sí, probablemente tengas razón. No pensé mucho en eso en ese momento; Solo quería que las firmas de las 3 funciones coincidieran: P
deadlydog
usando el método append, serializando muchos objetos en el mismo archivo, ¿cómo los deserializo? ¿Cómo busco en la corriente?
John Demetriou
1
Agregue el comentario al serializador binario que notificará a las personas que los datos resultantes están sellados con el nombre seguro del ensamblado y los cambios en las versiones de este sin agregar enlaces de redireccionamiento o ejecutar en entornos que no respetan dichos enlaces (por ejemplo, powershell). fail
zaitsman
1
@JohnDemetriou Si guarda varias cosas en un archivo, recomendaría envolver los objetos en alguna forma de objeto de contexto y serializar ese objeto (deje que el administrador de objetos analice las partes que desee). Si está intentando guardar más datos de los que puede almacenar en la memoria, es posible que desee cambiar a un almacén de objetos (base de datos de objetos) en lugar de un archivo.
Tezra
30

Deberá serializar en algo: es decir, elegir binario o xml (para serializadores predeterminados) o escribir código de serialización personalizado para serializar en alguna otra forma de texto.

Una vez que haya elegido eso, su serialización (normalmente) llamará a una secuencia que está escribiendo en algún tipo de archivo.

Entonces, con su código, si estuviera usando la serialización XML:

var path = @"C:\Test\myserializationtest.xml";
using(FileStream fs = new FileStream(path, FileMode.Create))
{
    XmlSerializer xSer = new XmlSerializer(typeof(SomeClass));

    xSer.Serialize(fs, serializableObject);
}

Luego, para deserializar:

using(FileStream fs = new FileStream(path, FileMode.Open)) //double check that...
{
    XmlSerializer _xSer = new XmlSerializer(typeof(SomeClass));

    var myObject = _xSer.Deserialize(fs);
}

NOTA: Este código no se ha compilado, y mucho menos se ha ejecutado; puede haber algunos errores. Además, esto supone una serialización / deserialización completamente lista para usar. Si necesita un comportamiento personalizado, deberá realizar un trabajo adicional.

AllenG
fuente
10

1. Restaurar objeto desde archivo

Desde aquí puede deserializar un objeto del archivo de dos formas.

Solución 1: lea el archivo en una cadena y deserialice JSON a un tipo

string json = File.ReadAllText(@"c:\myObj.json");
MyObject myObj = JsonConvert.DeserializeObject<MyObject>(json);

Solución 2: deserializar JSON directamente desde un archivo

using (StreamReader file = File.OpenText(@"c:\myObj.json"))
{
    JsonSerializer serializer = new JsonSerializer();
    MyObject myObj2 = (MyObject)serializer.Deserialize(file, typeof(MyObject));
}

2. Guardar objeto en archivo

desde aquí puede serializar un objeto para archivar de dos formas.

Solución-1: serialice JSON en una cadena y luego escriba la cadena en un archivo

string json = JsonConvert.SerializeObject(myObj);
File.WriteAllText(@"c:\myObj.json", json);

Solución 2: serialice JSON directamente en un archivo

using (StreamWriter file = File.CreateText(@"c:\myObj.json"))
{
    JsonSerializer serializer = new JsonSerializer();
    serializer.Serialize(file, myObj);
}

3. Extra

Puede descargar Newtonsoft.Json de NuGet siguiendo el comando

Install-Package Newtonsoft.Json
Emdadul Sawon
fuente
1

** 1. Convierta la cadena json en base64string y escríbala o añádala al archivo binario. 2. Lea base64string del archivo binario y deserialice usando BsonReader. **

 public static class BinaryJson
{
    public static string SerializeToBase64String(this object obj)
    {
        JsonSerializer jsonSerializer = new JsonSerializer();
        MemoryStream objBsonMemoryStream = new MemoryStream();
        using (BsonWriter bsonWriterObject = new BsonWriter(objBsonMemoryStream))
        {
            jsonSerializer.Serialize(bsonWriterObject, obj);
            return Convert.ToBase64String(objBsonMemoryStream.ToArray());
        }           
        //return Encoding.ASCII.GetString(objBsonMemoryStream.ToArray());
    }
    public static T DeserializeToObject<T>(this string base64String)
    {
        byte[] data = Convert.FromBase64String(base64String);
        MemoryStream ms = new MemoryStream(data);
        using (BsonReader reader = new BsonReader(ms))
        {
            JsonSerializer serializer = new JsonSerializer();
            return serializer.Deserialize<T>(reader);
        }
    }
}
invitado
fuente
0

Puede utilizar JsonConvert de la biblioteca Newtonsoft. Para serializar un objeto y escribir en un archivo en formato json:

File.WriteAllText(filePath, JsonConvert.SerializeObject(obj));

Y para deserializarlo nuevamente en un objeto:

var obj = JsonConvert.DeserializeObject<ObjType>(File.ReadAllText(filePath));
ozanmut
fuente