如何在写入文件时阻止对文件的访问,并在文件写入后恢复执行?

Posted

技术标签:

【中文标题】如何在写入文件时阻止对文件的访问,并在文件写入后恢复执行?【英文标题】:How can I prevent access to a file while it is being written to, and resume execution once the file has been written? 【发布时间】:2020-06-09 21:18:34 【问题描述】:

当我的服务器收到请求时,我运行我的函数foo。在foo 期间的某个时间点,我检查我的机器上是否存在某些文件(基于请求),然后我远程获取那些不存在的文件,并将它们保存在本地以备将来请求时使用。

如果我同时收到多个请求,这些请求都引用同一个文件bar,而我的服务器上不存在该文件,我会遇到问题。以下是所发生情况的示例时间表:

    请求 1 异步检查是否存在 bar 请求 2 异步检查是否存在 bar 请求1看到bar不存在,所以异步下载文件 请求2看到bar不存在,所以异步下载文件 请求 1 向bar 打开一个写入流,并将文件响应异步传送到该写入流中 请求 2 向bar 打开一个写入流,并将文件响应异步传送到该写入流中 请求 1 完成文件写入,尝试使用图像加载库加载其内容(图像),最终引发错误。

这是因为文件内容无效,因为文件正在被请求 2 覆盖。

我知道解决这个问题可能会涉及文件锁定,因此第一个看到文件在本地丢失的请求可以创建一个锁定文件,以向后续请求指示它已经被提取/写入。我不确定的是如何让这些后续请求等到文件加载完成。

我是否应该使用生成器函数,如果发现其他请求正在获取此远程文件,则暂停执行我的函数?在那种情况下,我以后如何恢复它?我是否必须维护一些暂停请求的全局队列?

是否有任何资源可以帮助我更好地理解在这里做什么?

【问题讨论】:

这是一个没有外部争用文件的服务器问题吗?或者这是一个多服务器问题和/或文件也存在外部争用。如果这是一个服务器问题,选项会简单得多。此外,请显示您拥有的任何实际代码的相关部分,因为您如何检查文件是否存在(以防止竞争条件)的详细信息也很重要。 【参考方案1】:

您将需要某种形式的同步。只要你只运行一个 NodeJS 进程,最简单的方法就是使用 javascript 的单线程行为:

  const fileLoading = new Map();

  async function getFile(id) 
    if(fileLoading.has(id)) 
      await fileLoading.get(id);
     else 
     const load = (async function() 
        await fetchFile(id);
        fileLoading.remove(id);
     )();
     fileLoading.set(id, load);
     await load;
   
   return await readFile(id);
 

【讨论】:

以上是关于如何在写入文件时阻止对文件的访问,并在文件写入后恢复执行?的主要内容,如果未能解决你的问题,请参考以下文章

如何从流中读取 CSV 文件并在写入时处理每一行?

如何锁定文件以防止读取/写入同一文件的多个 ajax 请求?

使用 NAudio 录制音频并在麦克风输入静音时写入文件

平滑运算符:在写入文件时重命名文件

EPERM 阻止的文件写入权限 - 删除然后写入新文件。节点.js

如何从 servlet-filter 写入文件并在 Eclipse 中读取它?