15

好的,所以我有一个程序可以将一些特定数据输出到制表符分隔的变量文件中。

我一直在使用 Excel 打开和查看文件内容,但是我发现 excel 坚持锁定它打开的每个文件非常烦人,因为如果我在 Excel 中打开文件,我的程序会崩溃......但我真的很喜欢每次运行程序后数据都会整齐地更新,因此我不必一直关闭并重新打开文件。

因此,我决定使用 Javascript 来解析文件并将其显示在 html 表格中是最简单的,而且确实如此。我很快就把东西撞到了一起。现在,如果我将文件保留在显示屏上,我的程序不会崩溃,但是,它仍然没有更新……而且我每次都必须打开新生成的文件。

所以,我想知道是否有一种机制可以让我的 Javascript 以某种方式通知另一个进程对文件的更改?我知道这不太可能,但我想避免出于明显的原因简单地轮询文件。

我对 JS 非常熟悉,但 HTML5 和新的 API 对我来说都是新的。

4

3 回答 3

11

我不相信File API有任何文件更改事件,只有进度事件等。

2020 年 8 月更新:下面的替代方案不再有效,规范明确禁止它,指出File对象的信息必须反映基础文件在被选中时的状态。从规范:

用户代理应努力将 File 对象的快照状态设置为获取引用时磁盘上底层存储的状态。如果在进行引用之后文件在磁盘上被修改,则文件的快照状态将不同于底层存储的状态。


你可以使用轮询。记住 的lastModifiedDateFile然后当您的轮询函数触发时,获取File输入的新实例并查看 是否lastModifiedDate已更改。

这适用于我在 Chrome 上,例如:Live Copy | 来源

(function() {
  var input;
  var lastMod;

  document.getElementById('btnStart').onclick = function() {
    startWatching();
  };
    function startWatching() {
        var file;

        if (typeof window.FileReader !== 'function') {
            display("The file API isn't supported on this browser yet.");
            return;
        }

        input = document.getElementById('filename');
        if (!input) {
            display("Um, couldn't find the filename element.");
        }
        else if (!input.files) {
            display("This browser doesn't seem to support the `files` property of file inputs.");
        }
        else if (!input.files[0]) {
            display("Please select a file before clicking 'Show Size'");
        }
        else {
            file = input.files[0];
      lastMod = file.lastModifiedDate;
            display("Last modified date: " + lastMod);
      display("Change the file");
      setInterval(tick, 250);
        }
    }

  function tick() {
    var file = input.files && input.files[0];
    if (file && lastMod && file.lastModifiedDate.getTime() !== lastMod.getTime()) {
      lastMod = file.lastModifiedDate;
            display("File changed: " + lastMod);
    }
  }

  function display(msg) {
    var p = document.createElement('p');
    p.innerHTML = msg;
    document.body.appendChild(p);
  }
})();
<input type='file' id='filename'>
<input type='button' id='btnStart' value='Start'>

于 2013-01-11T18:14:39.190 回答
5

这个问题有两种解决方案,而且<input type="file">不是其中之一。根据规范,它会创建文件的“快照”。


本机文件系统

api是实验性的,需要在闪烁时启用标志(又名 chromium 浏览器)。这个想法是你得到一个文件句柄,当你需要文件时,你调用异步“getFile”函数来检索实际文件。

此功能是一项“强大功能”,需要您的网站安全,并且无法在沙盒 iframe 中使用。

所以这里没有测试是一些“黑暗中的代码”:

// triggerd on click
async function pickFile () {
  const handle = showOpenFilePicker()
  let lastModificationTime = 0
  
  async function compare () {
    const file = await handle.getFile()
    if (file.lastModified > lastModificationTime) {
      lastModificationTime = +file.lastModified
      console.log(await file.text())
    }
  }
  
  setInterval(compare, 1000)
}

通过拖放获取条目

与本机文件系统类似,您也可以检索文件句柄并执行相同的操作,但此功能适用于当今的所有浏览器。但是这个代码片段在 stackoverflow 中不起作用,因为它使用了一些沙盒使其不兼容,所以这里一些评论

function drop(event) {
  event.stopPropagation();
  event.preventDefault();
    
  // get the file as an fileEntry (aka file handle)
  const fileEntry = event.dataTransfer.items[0].webkitGetAsEntry()
  let lastModificationTime = 0
  
  async function read (file) {
    // use the new async read method on blobs.
    console.log(await file.text())
  }
  
  function compare (meta) {
    if (meta.modificationTime > lastModificationTime) {
      lastModificationTime = meta.modificationTime
      fileEntry.file(read)
    }
  }
  
  setInterval(fileEntry.getMetadata.bind(fileEntry, compare), 1000)
}

编辑:现在还有一种方法可以将拖放文件作为 FileSystemFileHandle 更好地使用

elem.addEventListener('dragover', evt => {
  // Prevent navigation.
  evt.preventDefault()
})
elem.addEventListener('drop', async evt => {
  // Prevent navigation.
  evt.preventDefault()

  // Process all of the items.
  for (const item of evt.dataTransfer.items) {
    // kind will be 'file' for file/directory entries.
    if (item.kind === 'file') {
      const entry = await item.getAsFileSystemHandle();
      if (entry.kind === 'file') {
        // use same solution as the first Native File System solution
      }
    }
  }
})
于 2020-05-29T20:20:07.583 回答
4

虽然 TJ Crowder 的回答是正确的,但 Chrome 的实现似乎违反了规范。

每个 Blob 都必须有一个内部快照状态,如果存在任何此类底层存储,则必须将其初始设置为底层存储的状态,并且必须通过结构化克隆进行保存。可以为文件找到快照状态的进一步规范定义。

选择文件时,输入具有此点的内容的快照。磁盘上的本地更改不会更新快照。

于 2017-02-17T12:01:55.980 回答