使用HTML5 File API检查文件是否已更改

时间:2013-01-11 18:09:40

标签: javascript html5

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

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

所以,我决定用最简单的方法来解析文件并将其显示在html表中,就是这样。我立刻把东西撞到了一起。现在,如果我将文件保留在显示状态,我的程序不会崩溃,但是,它仍然不会更新......我每次都必须打开新生成的文件。

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

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

3 个答案:

答案 0 :(得分:9)

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

您可以使用投票。请记住File的{​​{3}},然后当您的轮询功能触发时,为输入获取一个新的File实例,并查看lastModifiedDate是否已更改。

这适用于Chrome,例如:lastModifiedDate | Live Copy

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<title>Watch for a file change</title>
<style type='text/css'>
body {
    font-family: sans-serif;
}
</style>
</head>
<body>
<input type='file' id='filename'>
<input type='button' id='btnStart' value='Start'>
<script type='text/javascript'>
(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);
    }
})();
</script>
</body>
</html>

答案 1 :(得分:3)

而T.J.克劳德的答案是正确的,Chrome的实施似乎打破了规范。

  

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

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

答案 2 :(得分:2)

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


本地文件系统

api是实验性的,要求在眨眼时启用标志(又名Chrome浏览器)。这样做的目的是获得文件句柄,然后在需要文件时调用异步“ getFile”函数来检索实际文件。

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

因此,这里未经测试就是一些“黑暗中的代码”:

// triggerd on click
async function pickFile () {
  // const handle = showOpenFilePicker() // chrome 85
  const handle = await chooseFileSystemEntries() // deprecated (split up to 3 fns)
    let lastModificationTime = new Date(0)
  
  async function compare (meta) {
    const file = await handle.getFile()
    if (file.lastModifiedDate > lastModificationTime) {
      lastModificationTime = file.lastModifiedDate
      console.log(await file.text())
    }
  }
  
  setInterval(compare, 1000)
}

通过拖放获取条目

类似于本机文件系统,您还可以检索文件句柄并执行相同的操作,但是此功能在当今的浏览器中有效。但是此代码段在stackoverflow中不起作用,因为它使用了一些沙箱,使其变得不兼容,所以这里是fiddle,几乎没有注释

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 = new Date(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)
}