我正在使用Rx来监控文件的更改。
| window1 | | window2 | | window3 |
Time 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
Input M M M M M R
Output M M R
Input M M M M M M R
Output M M M R
(M - 修改,R - 重命名)
热门示例:最后一个窗口(11 - 14)没有剩余修改。
底部示例:最后一个窗口中的剩余修改(在t = 12)。
我上面的示例我每5秒采样一次以将修改操作限制为文件。即在每5秒窗口中,我只采用最新的修改操作。
我希望在重命名操作发生后立即停止采样 返回当前窗口中的最新修改(如果有)和重命名事件。
有些注意事项:
这是我到目前为止所拥有的。
var events = source
.GroupBy(e => e.FullPath)
.SelectMany(g => g.Sample(TimeSpan.FromSeconds(5)));
答案 0 :(得分:1)
这是一个解决方案 - 有点匆忙,所以我确信它可以整理,但似乎有效。这使用了Nuget包rx-testing
和ix-main
[sic - IEnumerable<T>.TakeLast()
]所需的。我已经将您的示例映射为已呈现,但是将一个时间单位表示为100个刻度。
请注意,您的问题中的第二个方案有一个错误 - 在收到重命名事件之前,无法发出上次修改的事件。由于这个原因,我的输出在1400时刻发出了两个事件。
主要查询如下(假设actions
包含FileAction
个事件):
发布操作,以便我们可以多次订阅:
actions.Publish(source => {
以500个刻度间隔显示操作,但在重命名时关闭窗口:
return source.Window(
() => Observable.Timer(TimeSpan.FromTicks(500), scheduler)
.Merge(source.Where(x => x == FileAction.Rename)
.Select(_ => 0L)))
停止Rename上的窗口流:
.TakeUntil(source.Where(x => x == FileAction.Rename))
将窗口展平为包含最后两个事件的列表流:
.SelectMany(x => x.TakeLastBuffer(2))
查找重命名作为最后一项,如果是重命名,则获取最后2项,否则只是最后一项。请注意,这是精心设计的,用于处理空列表或1个项目的列表。此外,再次使用SelectMany
将列表展平,以便我们留下一系列操作。
.SelectMany(l => {
return l.LastOrDefault() == FileAction.Rename
? l.TakeLast(2)
: l.TakeLast(1);
});
})
您可以订阅此内容以获取所请求的活动。以下是完整示例:
void Main()
{
var tests = new Tests();
tests.Scenario();
}
// Note inheritance of ReactiveTest to get OnXXX helpers
public class Tests : ReactiveTest
{
public enum FileAction
{
Modify,
Rename
}
public void Scenario()
{
var scheduler = new TestScheduler();
var actions = scheduler.CreateHotObservable<FileAction>(
OnNext(200, FileAction.Modify),
OnNext(300, FileAction.Modify),
OnNext(500, FileAction.Modify),
OnNext(700, FileAction.Modify),
OnNext(900, FileAction.Modify),
// Uncomment next line for
// scenario with mod + rename in last window
// OnNext(1200, FileAction.Modify),
OnNext(1400, FileAction.Rename));
actions.Publish(source => {
return source.Window(
() => Observable.Timer(TimeSpan.FromTicks(500), scheduler)
.Merge(source.Where(x => x == FileAction.Rename)
.Select(_ => 0L)))
.TakeUntil(source.Where(x => x == FileAction.Rename))
.SelectMany(x => x.TakeLastBuffer(2))
.SelectMany(l => {
return l.LastOrDefault() == FileAction.Rename
? l.TakeLast(2)
: l.TakeLast(1);
});
})
.Timestamp(scheduler) /* to show timings */
.Subscribe(x => Console.WriteLine(
"Event: {0} Timestamp: {1}",
x.Value, x.Timestamp.Ticks));
scheduler.Start();
}
}
输出:
Event: Modify Timestamp: 500
Event: Modify Timestamp: 1000
Event: Rename Timestamp: 1400
如果您取消注释第二种情况的标记线,则会获得:
Event: Modify Timestamp: 500
Event: Modify Timestamp: 1000
Event: Modify Timestamp: 1400
Event: Rename Timestamp: 1400