在Node.js中如何检查文件是否处于打开状态?

3

如果一个文件当前通过本地应用程序(.pdf -> pdf阅读器)打开,我该如何追踪它的打开状态?

我正在使用electron.js创建一个文件同步应用程序。因此,如果用户想要删除一个文件,我想检查它是否已经被打开。如果已经打开,我想显示一个警告。

文件仍然处于打开状态,请先关闭它。


如果打开文件描述符进行写操作,该文件将被锁定,并且您可以在第二次打开时捕获错误(这可能会因操作系统而有所不同)。然而,文件描述符仍然不会保持打开状态。PDF查看器将文件读入内存,然后关闭描述符。您将需要实现自己的跟踪器。假设您是打开PDF的人,这不会太困难。如果您不是打开PDF的人,则无法做到这一点。 - leitning
嗨,感谢您的评论。当我打开PDF/图片时,我可以设置一个状态为open: true。但是我还需要知道它何时关闭,以便我可以更新该状态。 - Debotos Das
你是怎么打开它的?监听子进程或浏览器窗口的关闭事件。 - leitning
我正在通过shell.openPath打开文件。它没有关闭事件。 - Debotos Das
这个回答解决了你的问题吗?Node.js在复制文件之前如何检查文件是否已打开 - pushkin
嗨,我試過了但沒有成功。相反地,這個套件 - https://github.com/ronomon/opened 使用一個 Promise 包裝器完美運作。 - Debotos Das
3个回答

2

目前,以下代码片段对我有效(在macOS上测试过)-

在主进程中 -

import util from 'util'
const exec = util.promisify(require('child_process').exec)

const checkFileIsOpen = async (fileName: string): Promise<boolean> => {
    try {
        const filePath = myAppDocsPath + '/' + fileName.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')

        const { stdout } = await exec('lsof ' + filePath)
        console.log('stdout:', stdout)

        if (stdout.length === 0) {
            // Not in use | File is not open
            return false
        } else {
            // In use | File is open
            return true
        }
    } catch (error) {
        console.log('Check file is open error:\n', error)
        return false
    }
}

https://github.com/ronomon/opened - 这对我来说似乎很有用。 - Debotos Das
对我有用。必须在文件路径周围加上引号,因为其中有空格。 - Steve

0

使用spawn函数,您将收到对子进程的引用,可以在其上监听exit事件。以下是一个简单的示例:

const {spawn} = require('child_process');
const PDF_BIN = '/path/to/pdf-viewer';

const fileTracker = {};

const openFile = (fileName) => {
  if(fileTracker[fileName])
    throw new Error(`${fileName} already open`);
  let args = ['-foo','--b','ar',fileName];
  let cp = spawn(PDF_BIN, args);
  fileTracker[fileName] = cp;
  cp.once('error',(err) => {
    console.error(err);
    console.log(`Error opening ${fileName}`);
    delete(fileTracker[fileName]);
  });
  cp.once('exit',(code,signal) => {
    if(signal)
      code = signal;
    if(code != 0)
      console.error(`Recieved exit code ${code} on file ${fileName}`);
    delete(fileTracker[fileName]);
  })  
}

谢谢。在我的案例文件中,文件类型可以是任何类型,如图片、Docx、PDF、Excel、演示文稿、文本、CSV等。而且我是通过系统原生应用程序打开每种类型的文件。具体而言,我不知道那个打开应用程序的bin二进制文件在哪里。 - Debotos Das

0

在一个包的帮助下(https://github.com/ronomon/opened),我找到了一个更好的解决方案 -

const checkFileIsOpen = async (fileName: string): Promise<boolean> => {
    try {
        // myAppDocsPath is a variable of my application specific path
        const filePath = myAppDocsPath + '/' + fileName
        const paths = [filePath]
        return new Promise((resolve, reject) => {
            Opened.files(paths, function (error: any, hashTable: Record<string, boolean>) {
                console.log(hashTable)
                if (error) throw reject(false)
                resolve(hashTable[paths[0]])
            })
        })
    } catch (error) {
        console.log('Check file is open error:\n', error)
        return false
    }
}

获取文件列表 -

type FileListOpenStatus = Record<string, boolean> | false

const checkFileListOpenStatus = async (fileNameList: string[]): Promise<FileListOpenStatus> => {
    try {
        // myAppDocsPath is a variable of my application specific path
        const paths = fileNameList.map((fileName) => `${myAppDocsPath}/${fileName}`)
        return new Promise((resolve, reject) => {
            Opened.files(paths, function (error: any, hashTable: Record<string, boolean>) {
                console.log(hashTable)
                if (error) throw reject(false)
                const results: Record<string, boolean> = {}
                for (const [filePath, value] of Object.entries(hashTable)) {
                    const fileName = path.basename(filePath)
                    results[fileName] = value
                }
                resolve(results)
            })
        })
    } catch (error) {
        console.log('Check file list open status error:\n', error)
        return false
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接