C# - 使用protobuf直接写入zip文件

时间:2013-12-07 11:29:14

标签: c# protobuf-net system.io.packaging

我正在研究一种模拟器程序,该程序在文件中频繁地(> 10次)写入小数据(<1kB)。我使用Queue来存储这些数据,当这个队列有300个或更多成员时,它会将数据写入存储在zip文件中的文件并清除队列。

当我解压缩zip文件并检查输出文件(更具体地说:flush)时,问题是暂停或停止模拟(在两种情况下都会调用Offsets.sdo)之后的问题写作(在我的代码中,调用flush)在文件中。同样在模拟期间,我创建的Zipfile(带有outFile字段)的大小为0。

我的文件编写器代码是:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.Packaging;
using System.Net.Mime;
using ProtoBuf;

namespace SEWS.History
{
    class HistoryWriterEngine : HistoryEngine ,HistoryWriter
    {
        public static readonly string OUTPUT_DATA_FILE_NAME = "SimulationOutdata.sod";
        public static readonly string OFFSETS_FILE_NAME = "Offsets.sdo";

        #region buffer
        private static readonly int MAXIMUM_BUFFER_SIZE = 300; // half a minute of simulation with 0.1s steps
        private Queue<SEWS.SimulationEngine.SimulationOutputData> buffer = new Queue<SEWS.SimulationEngine.SimulationOutputData>();
        private Dictionary<string, PackagePart> packageParts = new Dictionary<string, PackagePart>();
        #endregion

        #region IO
        private ZipPackage outFile;
        public override void initFile(string address)
        {
            if (outFile != null)
            {
                flush();
                closeFile();
            }
            workingFile = address;

            outFile = (ZipPackage)ZipPackage.Open(workingFile, FileMode.Create);

            getNewStream(OUTPUT_DATA_FILE_NAME);
            getNewStream(OFFSETS_FILE_NAME, MediaTypeNames.Text.Plain);
        }

        public override void closeFile()
        {
            flush();
            outFile.Flush();
            outFile.Close();
            outFile = null;
        }

        public Stream getNewStream(string fileName, string type = MediaTypeNames.Application.Octet)
        {
            PackagePart packagePart;
            packagePart = outFile.CreatePart(
                PackUriHelper.CreatePartUri(new Uri(fileName, UriKind.Relative)),
                type,
                CompressionOption.SuperFast);

            packageParts.Add(fileName, packagePart);
            return packagePart.GetStream();
        }

        public Stream getStream(string fileName)
        {
            if (packageParts.ContainsKey(fileName))
            {
                return (packageParts[fileName] as PackagePart).GetStream();
            }
            else
            {
                throw new NullReferenceException("No such file as " + fileName + " found.");
            }
        }
        #endregion

        #region HistoryWriterImpl
        public void writeOutputData(SEWS.SimulationEngine.SimulationOutputData data)
        {
            buffer.Enqueue(data);
            if (buffer.Count >= MAXIMUM_BUFFER_SIZE)
            {
                flush();
            }
        }
        System.Diagnostics.Stopwatch s = new System.Diagnostics.Stopwatch();
        public void flush()
        {
            Stream outStream = getStream(OUTPUT_DATA_FILE_NAME);
            Stream offsetsStream = getStream(OFFSETS_FILE_NAME);
            StreamWriter offsetsWriter = new StreamWriter(offsetsStream);

            SEWS.SimulationEngine.SimulationOutputData currentData;
            Console.WriteLine("Writing " + buffer.Count + " records");
            s.Restart();
            while (buffer.Count > 0)
            {
                currentData = buffer.Dequeue();
                Serializer.SerializeWithLengthPrefix(outStream, currentData, PrefixStyle.Base128, 1);
                offsetsWriter.Write(
                    new StringBuilder()
                    .Append(currentData.CurrentStep.ToString())
                    .Append(' ')
                    .Append(currentData.CurrentTime.TimeSinceStart.ToString())
                    .Append(' ')
                    .Append(outStream.Position)
                    .Append("\r\n")
                    .ToString()
                );
            }
            s.Stop();
            Console.WriteLine("Took " + s.ElapsedMilliseconds + " ms.");

            outStream.Flush();
            offsetsWriter.Flush();
            offsetsStream.Flush();
            outStream.Close();
            offsetsWriter.Close();
            offsetsStream.Close();

            outFile.Flush();
        }
        #endregion
    }
}

输出是:

Writing 300 records
Took 138 ms.
Writing 300 records
Took 18 ms.
Writing 300 records
Took 14 ms.
Writing 300 records
Took 14 ms.
Writing 300 records
Took 14 ms.
Writing 41 records
Took 5 ms.

前5次写入是自动的,最后一次(41次记录)是关于模拟中的暂停。

1 个答案:

答案 0 :(得分:2)

您的代码反复调用flush()flush()内的意图似乎是通过getStream()重用文件。

但是在flush()的尾端,有一个outStream.Close();的调用,因此getStream()必须始终创建一个新文件。在Overwrite模式下显然。