今天另一个Rx问题:)
简单地说,我正在使用异步IO来操作Streams。但是,众所周知,在使用异步读取时,我们不一定得到所需的所有字节 - 因此在XAsync
方法上返回int。我想知道如何告诉Rx Observable
重试读取没有从Stream中读取正确数量的字节并以正确的数量偏移?
目前,我有这个,但不知道如何在ReadAsync中设置offset参数。
private IDisposable _streamMessageContract;
private readonly byte[] _readBuffer = new byte[8024];
public void Start()
{
// Subscribe to the stream for dataz
_streamMessageContract = Observable.FromAsync<int>(() => _stream.ReadAsync(_readBuffer, 0, _readBuffer.Length))
.Repeat()
.Subscribe(
y => _RawBytesReceived(_readBuffer, y),
ex => _Exception(ex),
() => _StreamClosed());
}
#region Helpers
private void _RawBytesReceived(byte[] bytes, int actualBytesRead)
{
}
private void _StreamClosed()
{
}
private void _Exception(Exception e)
{
}
#endregion
答案 0 :(得分:1)
最简单的方法是在闭包中使用局部变量,加上Defer
强制observable在每次迭代时重新计算其函数。
假设你想在当前程序段结束后继续阅读下一个程序段,你最终会得到类似的东西......
// An observable that will yield the next block in the stream.
// If the resulting block length is less than blockSize, then the
// end of the stream was reached.
private IObservable<byte[]> ReadBlock(Stream stream, int blockSize)
{
// Wrap the whole thing in Defer() so that we
// get a new memory block each time this observable is subscribed.
return Observable.Defer(() =>
{
var block = new byte[blockSize];
int numRead = 0;
return Observable
.Defer(() => Observable.FromAsync<int>(() =>
stream.ReadAsync(block, numRead, block.Length - numRead)))
.Do(y -=> numRead += y)
.Repeat()
.TakeWhile(y => y > 0 && numRead != blockSize) // take until EOF or entire block is read
.LastOrDefaultAsync() // only emit the final result of this operation
.Select(_ =>
{
// If we hit EOF, then resize our result array to
// the number of bytes actually read
if (numRead < blockSize)
{
block = block.Take(numRead).ToArray();
}
return block;
});
});
}
public void Start()
{
// Subscribe to the stream for dataz.
// Just keep reading blocks until
// we get the final (under-sized) block
_streamMessageContract = ReadBlock(stream, 8024)
.Repeat()
.TakeWhile(block => block.Length == 8024) // if block is small then that means we hit the end of the stream
.Subscribe(
block => _RawBytesReceived(block),
ex => _Exception(ex),
() => _StreamClosed());
}