我正在尝试将下面的类转换为lazily返回一个文件。
public class ObservableFile2 : IObservable<string>
{
private readonly IObservable<string> subject;
public ObservableFile2(string fileName)
{
subject = Observable.Using<string, StreamReader>
(
() => new StreamReader(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)),
streamReader => ObserveLines(streamReader)
);
}
private IObservable<string> ObserveLines(StreamReader streamReader)
{
return ReadLines(streamReader).ToObservable();
}
private IEnumerable<string> ReadLines(StreamReader streamReader)
{
while (!streamReader.EndOfStream)
{
yield return streamReader.ReadLine();
}
}
public IDisposable Subscribe(IObserver<string> observer)
{
return subject.Subscribe(observer);
}
}
我现在正尝试将其转换为使用
StreamReader.ReadLineAsync()
甚至更好的是将数据分块,即
await SourceStream.ReadAsync(buffer, 0, chunkSize).
我似乎没有掌握如何 包装和解包任务
欢迎提供援助。
由于
答案 0 :(得分:8)
我不是 Rx主人,所以可能有比我的回答更好的方法。
我认为应该可以使用async
启用Create
:
public static class ObservableFile2
{
public static IObservable<string> Create(string fileName)
{
return Observable.Create<string>(async (subject, token) =>
{
try
{
using (var streamReader = new StreamReader(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
while (true)
{
token.ThrowIfCancellationRequested();
var line = await streamReader.ReadLineAsync();
if (line == null)
{
subject.OnCompleted();
return;
}
subject.OnNext(line);
}
}
}
catch (Exception ex)
{
subject.OnError(ex);
}
});
}
}
答案 1 :(得分:0)
我不知道您的解决方案是否需要async-features,因为您没有提及它 - 我只能看到您想要“懒洋洋地”使用该文件 - 我的猜测是您希望获得一次一行,如果是这样,这个应该做的伎俩:
public static IEnumerable<string> EnumerateLines(string fileName)
{
using (
var streamReader =
new StreamReader(new FileStream(fileName,
FileMode.Open,
FileAccess.Read,
FileShare.Read)))
{
while (true)
{
if (streamReader.EndOfStream)
yield break;
Console.WriteLine("read another line...");
yield return streamReader.ReadLine();
}
}
}
请注意,这仅取决于StreamReader.ReadLine的实现细节。 您可以尝试通过使用Lazy来进行非严格评估 - 但是然后您会因为丢失文件句柄而遇到麻烦,因为您不知道值何时被消耗掉(即使Haskell有这个问题:)) - 我的建议:不要尝试使用文件 lazy ...这可以让你轻松陷入困境