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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14284124/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 21:13:14  来源:igfitidea点击:

Check if file has changed using HTML5 File API

javascripthtml

提问by Luke

Okay, so I have a program which outputs some specific data to a tab separated variable file.

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

I had been using Excel to open and view the file contents, however I found excel's insistence on locking every file it opens to be incredibly annoying as my program would crash if I left the file open in Excel... but I would really like the data to neatly update after each run of the program, so I don't have to close and re-open the file all the time.

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

So, I decided it would be easiest to use Javascript to parse the file and display it in a html table, and it was. I knocked something together in no time. Now my program doesn't crash if I leave the file on display, however, it still doesn't update... and I have to open the newly generated file each time.

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

So, I was wondering if there was a mechanism by which my Javascript could be somehow notified of a change to the file by another process? I know this is unlikely, but I would like to avoid simply polling the file for obvious reasons.

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

I am very familiar with JS, but HTML5 and the new APIs are all new to me.

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

回答by T.J. Crowder

I don't believe the File APIhas any event for the file changing, just progress events and the like.

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

You could use polling. Remember the lastModifiedDateof the File, and then when your polling function fires, get a new Fileinstance for the input and see if the lastModifiedDatehas changed.

你可以使用轮询。记住lastModifiedDateFile,然后当你的查询功能火灾,得到一个新的File实例的输入,看看是否lastModifiedDate已经改变。

This works for me on Chrome, for instance: Live Copy| Source

这在 Chrome 上对我有用,例如: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>

回答by Teffen Ellis

While T.J. Crowder's answer is correct, Chrome's implementation appears to break the spec.

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

Each Blob must have an internal snapshot state, which must be initially set to the state of the underlying storage, if any such underlying storage exists, and must be preserved through structured clone. Further normative definition of snapshot state can be found for files.

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

When a file is selected the input has a snapshot of the contents at that point. Local changes on disk don't update the snapshot.

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

回答by Endless

There is two solutions to this problem, and <input type="file">is not one of them. according to the spec, it creates a "snapshot" of the file.

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



Native File System

本地文件系统

This apiis experimental and requires flags to be enabled in blink (aka chromium browsers). The idea is that you get a file handle and when you need the file then you call the async "getFile" function to retrieve the actual file.

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

this feature is a "power feature" and require your site to be secure, and it can't work in sandboxed iframes

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

So without testing here is some "code in the dark":

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

// triggerd on click
async function pickFile () {
  const handle = await chooseFileSystemEntries()
    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)
}


Get Entry from Drag and drop

从拖放中获取条目

Similar to the native file system you can also retrieve a file handle and do the same thing, but this feature works in browsers today. but this code snippet don't work in stackoverflow since it use some sandboxing do making it inkompatible, so here is a fiddlewith few comments

与本机文件系统类似,您也可以检索文件句柄并执行相同的操作,但此功能目前适用于浏览器。但是这个代码片段在 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 = 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)
}