使用IEnumerators检查反序列化的进度

Mat*_*ski 0 c# binaryformatter unity-game-engine deserialization

public static object Deserialize(string path)
{
    using (Stream stream = File.Open(path, FileMode.Open))
    {
        BinaryFormatter bformatter = new BinaryFormatter();
        return bformatter.Deserialize(stream);
    }
}
SomeClass someObject = (SomeClass)Deserialize(savePath);
Run Code Online (Sandbox Code Playgroud)

我想创建一个包含自身进度的反序列化过程.所以可能某种IEnumerator每帧更新我的进度字段.是否可以在读取文件时跟踪Formatter的位置?

当我反序列化大文件时,我想知道它是怎么回事......

Iva*_*alo 6

我认为最简单的方法是通过包装正在反序列化的Stream来跟踪它,并在Formatter读取它时跟踪位置.

public class ReadProgressStream : ContainerStream
    {
        private int _lastProgress = 0;

        public ReadProgressStream(Stream stream) : base(stream) 
        {
            if (stream.Length <= 0 || !stream.CanRead) throw new ArgumentException("stream");
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            int amountRead = base.Read(buffer, offset, count);
            if (ProgressChanged != null)
            {
                int newProgress = (int)(Position * 100.0 / Length);
                if (newProgress > _lastProgress)
                {
                    _lastProgress = newProgress;
                    ProgressChanged(this, new ProgressChangedEventArgs(_lastProgress, null));
                }
            }
            return amountRead;
        }

        public event ProgressChangedEventHandler ProgressChanged;
    }
Run Code Online (Sandbox Code Playgroud)

用法:

public static T Deserialize<T>(
  Stream stream, ProgressChangedEventHandler callback)
{
  using (ReadProgressStream rps = new ReadProgressStream(stream))
  using (BufferedStream bs = new BufferedStream(rps))
  {
    rps.ProgressChanged += callback;
    BinaryFormatter formatter = new BinaryFormatter();
    return (T)formatter.Deserialize(bs);
  }
}
Run Code Online (Sandbox Code Playgroud)

ContainerStream:

public abstract class ContainerStream : Stream
    {
        private Stream _stream;

        protected ContainerStream(Stream stream)
        {
            if (stream == null) throw new ArgumentNullException("stream");
            _stream = stream;
        }

        protected Stream ContainedStream { get { return _stream; } }

        public override bool CanRead { get { return _stream.CanRead; } }

        public override bool CanSeek { get { return _stream.CanSeek; } }

        public override bool CanWrite { get { return _stream.CanWrite; } }

        public override void Flush() { _stream.Flush(); }

        public override long Length { get { return _stream.Length; } }

        public override long Position
        {
            get { return _stream.Position; }
            set { _stream.Position = value; }
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            return _stream.Read(buffer, offset, count);
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            return _stream.Seek(offset, origin);
        }

        public override void SetLength(long value)
        {
            _stream.SetLength(value);
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            _stream.Write(buffer, offset, count);
        }
    }
Run Code Online (Sandbox Code Playgroud)