在单个文件中组合数据集和其他数据的最简单方法?

时间:2010-05-28 13:48:42

标签: c# stream

我在C#中有一个数据集,我可以使用dataset.WriteXml(filename);进行序列化,但我希望该文件也包含其他数据(基本上是关于数据集的一些元数据)。

我可以在包含元数据的数据集中添加另一个表,但如果可能的话,我宁愿将它保持分开。

基本上我认为我想创建一个'文件组合'文件,看起来像这样:

size_of_file1
file1
size_of_file2
file2
... etc

然后,我想将文件加载到内存中,并将文件拆分为单独的流,以便我可以将数据集输入dataset.ReadXml(stream);,将元数据输入其他内容。

听起来可能吗?谁能告诉我怎么做呢?

由于


PS。我希望生成的文件保持人类可读性。

4 个答案:

答案 0 :(得分:1)

这是可能的。

您应该将其设为二进制(非人类可读)文件,并使用BinaryWriterBinaryReader类来读取和写入长度。

您可以像这样读取文件:

using (FileStream combinedFile = File.Open(...))
using (var binReader = new BinaryReader(combinedFile)) {
    while(!combinedFile.EOF) {
        long segmentLength = binReader.ReadInt64();

        var bytes = new byte[segmentLength];
        long totalRead = 0;
        while(bytesRead < segmentLength) {
            int read = combinedFile.Read(bytes, totalRead, Math.Min(4096, segmentLength - totalRead));
            if (read == 0)
                throw new InvalidDataException();
        }

        yield return new MemoryStream(bytes);
    }
}

编辑要制作人类可读的文件,请将段长度写为固定长度的字符串(填充到一些合理的位数,例如16),可选地后跟换行符。最大段大小是字符串的长度。

您可以像这样读取文件:

const int LengthPadding = 16

using (FileStream combinedFile = File.Open(...))
using (var binReader = new BinaryReader(combinedFile)) {
    while(!combinedFile.EOF) {
        char[] segmentLengthChars = binReader.ReadChars(16);

        long segmentLength = long.Parse(new string(segmentLengthChars));

        binReader.ReadChars(2);  //Skip the newline

        var bytes = new byte[segmentLength];
        long totalRead = 0;
        while(bytesRead < segmentLength) {
            int read = combinedFile.Read(bytes, totalRead, Math.Min(4096, segmentLength - totalRead));
            if (read == 0)
                throw new InvalidDataException();
        }

        yield return new MemoryStream(bytes);
    }
}

要编写段长度,请调用

binWriter.WriteChars(length.ToString().PadLeft(16, '0').ToCharArray());
binWriter.WriteChars(new char[] { '\r', '\n' });

您应该明确传递编码,CultureInfo.InvariantCulture适用。

答案 1 :(得分:1)

您可以扩展DataSet对象,将元数据添加为属性并序列化...

答案 2 :(得分:1)

如果需要人类可读,请使用XML文件。将元数据存储在元素中,将数据集存储在另一个元素中。

This thread will show you how

答案 3 :(得分:1)

如果你想简单地将XML写出一个节点,就像这样:

DataSet ds;
// populate ds with some data
string serialized;
using (System.IO.StringWriter sw = new System.IO.StringWriter())
{
   string metaData = "<MetaData version=\"1.0\" date=\"" + System.Xml.XmlConvert.ToString(DateTime.Now) + "\">" +
      "<Detail>Some more details</Detail></MetaData>";
   sw.Write(metaData);
   ds.WriteXml(sw, System.Data.XmlWriteMode.WriteSchema);
   sw.Close();
   serialized = sw.ToString();
}

然后你可以把它读作像这样的XML文档片段中的一系列节点,利用数据集使用XMLReader的能力:

using (System.IO.StringReader sr = new System.IO.StringReader(serialized))
{
   System.Xml.XmlReaderSettings xs = new System.Xml.XmlReaderSettings();
   xs.ConformanceLevel = System.Xml.ConformanceLevel.Fragment;
   System.Xml.XmlReader xr = System.Xml.XmlTextReader.Create(sr, xs);
   xr.Read();
   string metaData = xr.ReadOuterXml();
   Console.WriteLine(metaData);
   ds = new System.Data.DataSet();
   ds.ReadXml(xr);
   ds.WriteXml(Console.Out);
}