Reputation: 1186
I'm serializing an object (of class Car) and saving it as an xml file. However sometimes (very rare event, I can't replicate it) I get a file that contains only null characters (characters with 0 ASCII code), even though the file size is correct.
public void SaveCar(Car car)
{
var serializer = new XmlSerializer(typeof(Car));
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, car);
byte[] binaryCar = stream.ToArray();
FileHelper.WriteAllBytes(@"C:\car.xml", binaryCar);
}
}
FileHelper.WriteAllBytes is the same as System.IO.File.WriteAllBytes, except that it creates the parent directory if it doesn't exist.
public static class FileHelper
{
public static void WriteAllBytes(string path, byte[] bytes)
{
CreateParentDirectoryForPathIfDoesntExist(path);
File.WriteAllBytes(path, bytes);
}
public static void CreateParentDirectoryForPathIfDoesntExist(string filePath)
{
var file = new FileInfo(filePath);
if (file.Exists)
{
return;
}
if (file.Directory != null && !file.Directory.Exists)
{
Directory.CreateDirectory(file.Directory.FullName);
}
}
}
Any idea what can cause this? Encoding issues?
Upvotes: 1
Views: 1358
Reputation: 128
Your 'SaveCar' method seams to work nicely, but I you want you can use following implementation
public class XmlCar {
public static readonly Encoding Utf8Encoding = Encoding.UTF8;
public static readonly XmlSerializer CarSerializer = new XmlSerializer(typeof(Car));
public static Car Load(string path) {
using (var stream = new StreamReader(path, Utf8Encoding, false)) {
using (var reader = XmlReader.Create(stream)) {
return (Car)CarSerializer.Deserialize(reader);
}
}
}
public static void Save(string path, Car instance) {
using (var stream = new StreamWriter(path, false, Utf8Encoding)) {
using (var writer = XmlWriter.Create(stream)) {
CarSerializer.Serialize(writer, instance);
}
}
}
}
The biggest difference from yours example is that serializer-instance is created once and UTF8 encoding is forced.
Your method was tried with following classes
[XmlRoot]
public class Car {
[XmlAttribute]
public string Model { get; set; }
[XmlAttribute]
public string Plate { get; set; }
[XmlArray]
[XmlArrayItem]
public List<Part> Parts { get; set; }
}
[XmlRoot]
public class Part {
[XmlAttribute]
public string Type { get; set; }
[XmlAttribute]
public string Code { get; set; }
[XmlAttribute]
public int Quantity { get; set; }
}
Please note that this sample is derived from samples found on this site.
Yours method was changed a bit to accommodate some control over file name.
public static void SaveCar(Car car, int i)
{
var serializer = new XmlSerializer(typeof(Car));
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, car);
byte[] binaryCar = stream.ToArray();
File.WriteAllBytes("car"+ i + ".xml", binaryCar);
}
}
Method was tested with following function
static void Main(string[] args) {
var random = new Random();
var cars = new List<Car>();
for (var c = 0; c < 10; c++) {
var car = new Car() {
Model = Guid.NewGuid().ToString(),
Plate = (random.Next(500) + 500).ToString(),
Parts = new List<Part>()
};
for (var p = 0; p < 100; p++) {
car.Parts.Add(new Part() {
Type = Guid.NewGuid().ToString(),
Code = (random.Next(500) + 1500).ToString(),
Quantity = random.Next(100) + 1
});
}
SaveCar(car, c);
cars.Add(XmlCar.Load("car" + c + ".xml"));
}
}
Upvotes: 1