我有一些大型数据文件,我可以使用专门为此设计的 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/