我有一个goroutine,它定期检查目录中的新文件,然后打印文件的内容。但是,还有另一个goroutine可以创建一个文件,然后将内容写入其中,然后保存该文件。
如何忽略目录中以WRITE模式打开的文件?
示例代码:
for {
fileList, err := ioutil.ReadDir("/uploadFiles")
if err != nil {
log.Fatal(err)
continue
}
for _, f := range fileList {
log.Println("File : ", f.Name())
go printContents(f.Name())
}
time.Sleep(time.Second * 5)
}
在printContents goroutine中,我想忽略以WRITE模式打开的文件。
答案 0 :(得分:0)
这不是怎么做。
我可以想到以下这些选择:
如果两个goroutine都在同一程序中运行, 几乎没有问题:使“生产者” goroutine寄存器 已完成修改为某些文件的文件名 注册表,并读取(删除)“消费者” goroutine 从该注册表中。
在最简单的情况下,它可能是缓冲的通道。
如果生产者的工作速度比消费者快得多, 而且您由于某种原因不想阻止前者 那么由互斥锁保护的切片就可以满足要求。
如果goroutine在相同的不同进程中工作 机器,但您控制两个程序,使生产者 流程将相同的数据传达给使用者流程 通过任何合适的IPC。
哪种方法做IPC更好,取决于如何 进程启动,交互等。
有多种选择。
如果您同时控制两个进程,但又不想弄乱
它们之间的IPC(也有原因),然后使生产者
遵循有关如何写入文件的最佳做法
(稍后会详细介绍),并让消费者使用任何
文件系统监视工具,用于报告生产者生产后创建(“显示”)哪些文件。
您可以从github.com/fsnotify/fsnotify
开始。
要正确写入文件,生产者必须写入文件 数据到一个临时文件,即位于同一文件中的一个文件 目录,但文件名易于理解 表示文件尚未完成,例如, “ .foobar.data.part”或“ foobar.data.276gd14054.tmp”可以写入“ foobar.data”。 (存在其他方法,但是这种方法足以 开始。)
文件准备好后,生产者必须重命名
文件从其临时名称到其“适当”的最终名称。
此操作在所有明智的OS /文件系统上都是原子的,
并从PoV原子地使文件“跳入existense”
的消费者。例如inotify
on Linux generates
an event of type "moved to" for such an appearance。
如果您不想自己做正确的事情,那么github.com/dchest/safefile
是跨平台的好起点。
如您所见,通过这种方法,您知道 该文件仅根据报告的事实完成 出现了。
如果您不控制生产者,则可能需要诉诸 猜。
最简单的方法是再次监视文件系统 事件-但这一次是“文件更新”事件,而不是“文件已创建”事件 事件。对于每个报告为已更新的文件,您都必须记住 该事件的时间戳记,并且经过一定时间后,您可以声明该文件是由生产者完成的。
IMO,这种方法是最糟糕的,但是如果您没有 更好的选择至少是一些东西。