.net - 从数据 block 创建.Net Stream

标签 .net wcf stream

我有一些大型数据文件,我可以使用专门为此设计的 API 以 32kb 的 block 进行检索。 API 的一种用法如下:

LargeFileAPI lfa = new LargeFileAPI("file1.bin");
bool moredata = true;
List<byte[]> theWholeFile = new List<byte[]>();
while ( moredata  ) 
{
  byte[] arrayRead = new byte[32768];
  moredata = lfa.Read(arrayRead);
  theWholeFile.Add(arrayRead);
}

上面的问题是读取它所占用的内存与大文件的大小(假设为 100Mb)一样多。由于我想将其作为返回结果传递给 WCF 服务,因此我更愿意使用 Stream 作为服务的输出。

如何从中创建 Stream 对象并将其作为返回参数传递给 WCF 服务,而不占用内存中的完整文件大小?

我正在考虑创建一个继承自

的 LargeFileStream 类
System.IO.Stream

并重写 Read 方法。但我似乎无法弄清楚如何解决 Stream.Read 需要一个偏移量参数和要读取的字节数这一事实,因为我提到的 API 需要每次读取固定数量的字节。此外,我必须重写的所有其他方法呢,例如 Flush()、Position 以及其他任何方法。他们应该实现什么?我这样问是因为我不知道当我从客户端(WCF 服务的调用者)读取流时,WCF 除了 Stream.Read() 之外还会调用哪些其他函数。

此外,我需要它可序列化,以便它可以成为 WCF 服务的输出参数。

谢谢 圣战

最佳答案

您可以编写流来执行您想要的操作,使用 api 大小的一个缓冲区(即 32kb)并在读取时回收它。示例代码如下(并不是说它还没有准备好生产并且需要测试,而是让您开始):

public class LargeFileApiStream : Stream {
    private readonly LargeFileApi _api;
    private bool _hasMore;
    private bool _done;
    private byte[] _buffer;
    const int ApiBufferSize = 32768;
    public LargeFileApiStream(LargeFileApi api) {
        _api = api;    
    }

    public override void Flush() {
        // you can ignore that, this stream is not writable
    }

    public override long Seek(long offset, SeekOrigin origin) {
        throw new NotSupportedException(); // not seekable, only read from beginning to end
    }

    public override void SetLength(long value) {
        throw new NotSupportedException(); // not writable
    }        

    public override void Write(byte[] buffer, int offset, int count) {
        throw new NotSupportedException(); // not writable
    }

    public override int Read(byte[] buffer, int offset, int count) {
        // if we reached end of stream before - done
        if (_done)
            return 0;

        if (_buffer == null) {
            // we are just starting, read first block
            _buffer = new byte[ApiBufferSize];
            _hasMore = _api.Read(_buffer);
        }

        var nextIndex = _position % ApiBufferSize;
        int bytesRead = 0;
        for (int i = 0; i < count; i++) {
            if (_buffer.Length <= nextIndex) {
                // ran out of current chunk - fetch next if possible                    
                if (_hasMore) {
                    _hasMore = _api.Read(_buffer);
                }
                else {
                    // we are done, nothing more to read
                    _done = true;
                    break;
                }
                // reset next index back to 0, we are now reading next chunk
                nextIndex = 0;
                buffer[offset + i] = _buffer[nextIndex];
                nextIndex++;
                bytesRead++;
            }
            else {
                // write byte to output buffer
                buffer[offset + i] = _buffer[nextIndex];
                nextIndex++;
                bytesRead++;
            }                                                                
        }

        _position += bytesRead;
        return bytesRead;
    }

    public override bool CanRead {
        get { return true; }
    }
    public override bool CanSeek {
        get { return false; }
    }
    public override bool CanWrite {
        get { return false; }
    }
    public override long Length {
        get { throw new NotSupportedException(); }
    }

    private long _position;
    public override long Position
    {
        get { return _position; }
        set { throw new NotSupportedException(); } // not seekable
    }
}

关于.net - 从数据 block 创建.Net Stream,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36582880/

相关文章:

c# - ConfigureAwait(true) 仅适用于 4.6

c - 如何将 system() 命令输出流式传输到任何变量

rust - 如何将 `futures::Stream` 包装到任何实现 `Write` 的东西中?

Java 7 Try-With-Resources (AutoCloseable) 实现

c# - 以编程方式为 WCF (NetTcpBinding) 指定自定义授权

c# - 如何使用 .net 实现 SQL IN() 的等价物

c# - 检测 PNG 图像文件是否为透明图像?

.net - 当控件增长时如何使表单垂直和水平调整大小?

c# - 服务器证书与客户端证书

.net - 使用自定义ServiceHostFactory时是否需要Dispose()?