Làm thế nào để lưu / khôi phục đối tượng serializable vào / từ tệp?


94

Tôi có một danh sách các đối tượng và tôi cần lưu nó ở đâu đó trong máy tính của mình. Tôi đã đọc một số diễn đàn và tôi biết rằng đối tượng phải được Serializable. Nhưng sẽ rất tốt nếu tôi có thể lấy một ví dụ. Ví dụ: nếu tôi có những thứ sau:

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

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

Nhưng làm thế nào tôi có thể lưu trữ object1ở đâu đó trong máy tính của mình và sau đó lấy lại?


3
Dưới đây là một hướng dẫn mà chương trình làm thế nào để serialize vào một tập tin switchonthecode.com/tutorials/...
Brook

Câu trả lời:


142

Bạn có thể sử dụng như sau:

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

1
Đẹp! Mặc dù string attributeXml = string.Empty;in DeSerializeObjectkhông bao giờ được sử dụng;)
Jimbo

3
Không cần gọi phương thức đóng trên trình đọc trong khối đang sử dụng của bạn. Dispose () là ẩn và sẽ diễn ra ngay cả khi một ngoại lệ được đưa ra trong khối trước Close () rõ ràng. Khối mã rất hữu ích.
S. Brentson

2
Làm thế nào để tiết kiệm một danh sách các đối tượng sử dụng chức năng này, tôi đã sử dụng nó nhưng nó được tiết kiệm chỉ là đối tượng cuối cùng trong danh sách của tôi
Decoder94

1
Phương pháp này sẽ không tiết kiệm lĩnh vực nội bộ hoặc tư nhân, bạn có thể sử dụng này: github.com/mrbm2007/ObjectSaver
mrbm

152

Tôi vừa viết một bài đăng trên blog về việc lưu dữ liệu của một đối tượng vào Binary, XML hoặc Json . Bạn đúng là bạn phải trang trí các lớp của mình bằng thuộc tính [Serializable], nhưng chỉ khi bạn đang sử dụng Binary serialization. Bạn có thể thích sử dụng tuần tự hóa XML hoặc Json. Dưới đây là các chức năng để làm điều đó ở các định dạng khác nhau. Xem bài đăng trên blog của tôi để biết thêm chi tiết.

Nhị phân

/// <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

Yêu cầu lắp ráp System.Xml được bao gồm trong dự án của bạn.

/// <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

Bạn phải bao gồm một tham chiếu đến Newtonsoft.Json assembly, có thể lấy được từ Json.NET NuGet Package .

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

Thí dụ

// 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");

2
Tôi thích mã tuần tự hóa nhị phân của bạn. Nhưng trên WriteToBinaryFile tại sao bạn lại muốn thêm vào tệp? Có vẻ như bạn muốn tạo một tệp mới trong mọi trường hợp. Nếu không, sẽ có rất nhiều thông tin bổ sung về quá trình giải mã hóa.
công cộng không dây

1
@publicwireless Vâng, bạn có thể đúng. Tôi không nghĩ về nó nhiều vào lúc đó; Tôi chỉ muốn có chữ ký của 3 chức năng để phù hợp với: P
deadlydog

sử dụng phương pháp nối thêm, tuần tự hóa nhiều đối tượng trong cùng một tệp, làm cách nào để giải mã hóa chúng? làm cách nào để tìm kiếm trong luồng?
John Demetriou

1
Vui lòng thêm nhận xét vào trình tuần tự nhị phân sẽ thông báo cho mọi người rằng dữ liệu kết quả được đóng dấu bằng tên mạnh của hội đồng và thay đổi các phiên bản của điều này mà không thêm liên kết chuyển hướng hoặc chạy trong môi trường không tôn trọng các ràng buộc đã nói (ví dụ: powershell) sẽ thất bại
zaitsman

1
@JohnDemetriou Nếu lưu nhiều thứ vào một tệp, tôi khuyên bạn nên gói các đối tượng trong một số dạng đối tượng ngữ cảnh và tuần tự hóa đối tượng đó (Hãy để trình quản lý đối tượng phân tích cú pháp các phần bạn muốn). Nếu bạn đang cố gắng lưu nhiều dữ liệu hơn mức có thể giữ trong bộ nhớ, bạn có thể muốn chuyển sang một kho lưu trữ đối tượng (cơ sở dữ liệu đối tượng) thay vì một tệp.
Tezra

30

Bạn sẽ cần tuần tự hóa thành một cái gì đó: đó là, chọn nhị phân hoặc xml (đối với trình tuần tự hóa mặc định) hoặc viết mã tuần tự hóa tùy chỉnh để tuần tự hóa thành một số dạng văn bản khác.

Khi bạn đã chọn xong, quá trình tuần tự hóa của bạn (thông thường) sẽ gọi một Luồng đang ghi vào một số loại tệp.

Vì vậy, với mã của bạn, nếu tôi đang sử dụng Chuỗi tuần tự hóa 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);
}

Sau đó, để deserialize:

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

    var myObject = _xSer.Deserialize(fs);
}

LƯU Ý: Mã này chưa được biên dịch, hãy để một mình chạy - có thể có một số lỗi. Ngoài ra, điều này giả định việc tuần tự hóa / deserialization hoàn toàn ngoài hộp. Nếu bạn cần hành vi tùy chỉnh, bạn sẽ cần thực hiện thêm công việc.


10

1. Khôi phục đối tượng từ tệp

Từ đây, bạn có thể giải mã hóa một đối tượng từ tệp theo hai cách.

Giải pháp-1: Đọc tệp thành một chuỗi và giải mã hóa JSON thành một loại

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

Giải pháp-2: Hủy số hóa JSON trực tiếp từ một tệp

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

2. Lưu đối tượng vào tệp

từ đây, bạn có thể tuần tự hóa một đối tượng thành tệp theo hai cách.

Giải pháp-1: Tuần tự hóa JSON thành một chuỗi và sau đó ghi chuỗi vào một tệp

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

Giải pháp-2: Serialize JSON trực tiếp thành một tệp

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

3. Thêm

Bạn có thể tải xuống Newtonsoft.Json từ NuGet bằng lệnh sau

Install-Package Newtonsoft.Json

1

** 1. Chuyển đổi chuỗi json thành chuỗi base64 và Viết hoặc nối nó vào tệp nhị phân. 2. Đọc base64string từ tệp nhị phân và giải mã bằng 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);
        }
    }
}

0

Bạn có thể sử dụng JsonConvert từ thư viện Newtonsoft. Để tuần tự hóa một đối tượng và ghi vào tệp ở định dạng json:

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

Và để giải mã hóa nó trở lại thành đối tượng:

var obj = JsonConvert.DeserializeObject<ObjType>(File.ReadAllText(filePath));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.