输入文件大小和内容不会在macOS

时间:2018-05-16 12:06:07

标签: javascript html filereader

我写了一个基于Web的小工具,它使用文件输入来读取不断变化的文件。用户手动选择它(一次!)和更改它时的JavaScript跟踪(上次文件修改时间和文件大小)。如果已更改,则会再次读取文件内容。

这适用于Windows上的所有浏览器。但是在macOS上(在Safari 10.1.2和Firefox 51.0.1中测试),只有最后修改时间似乎会更新。文件大小未更新,似乎也无法再读取文件内容。所以我无法在macOS上跟踪浏览器中的文件更改。

但为什么呢?这是macOS中的安全限制吗?

请使用以下代码段进行测试。选择一个文件(例如文本文件),查看上次修改的时间戳和文件大小,然后更改文件并再次查看,如果大小已更改。在macOS上,文件大小不会改变。

请不要jQuery。



window.addEventListener('load', function() {
  window.setInterval(function() {
    var logFile = document.querySelector('#file').files[0];
    if (logFile) {
      document.querySelector('#info').innerHTML = '<br/>' +
        (new Date()).toString() + '<br/>Last modified: ' +
        logFile.lastModified +
        '<br/>Size: ' +
        logFile.size;
    }
  }, 1000);
});
&#13;
#info {
  font-family: Courier;
  font-size: 0.9em;
}
&#13;
<!DOCTYPE html>
<input type="file" id="file" />
<p id="info"></p>
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:3)

我不认为这是一种安全措施,而不仅仅是一种绩效衡量标准 一旦他们获得了文件元数据信息,他们就不再需要进一步获取=>&gt;较少访问用户的磁盘 说实话,我甚至有点惊讶,在Windows上,他们每次都会请求这些元数据。

要解决这个问题,这不是一件容易的事,我会重新考虑对此的需求,并且如果消息传递不能在另一个级别完成(例如来自修改文件的进程)。

事实上,在这种情况下,Firefox和Safari都不会表现相同:

  • 当你从输入中选择它时,Safari似乎会创建一个指向文件的blobURI,并且当你稍后尝试访问它时(例如从FileReader),它总是使用它。这里真正的问题是我们无法在磁盘上获得新版本,因为无论出于何种原因,这个blobURI似乎都是磁盘的真正指针。但是,如果我们只想检测文件更改,那么它对我们有好处,因为我们只需要检查FileReader.onerror事件,即使使用File.slice(0,1)也是如此(即最小的I / O)。

  • 另一方面,如果缓存的元数据的大小与已读取的元数据的大小不匹配,则Firefox将触发FileReader的错误 。这意味着您必须在每次检查时阅读整个文件,如果没有发生错误,请仔细检查数据是否实际相同...... ,在此浏览器中,您仍然可以使用blobURI从AJAX获取磁盘上的实际文件,以获取最新版本。

答案 1 :(得分:1)

我记得我之前一次又一次地读取文件输入时遇到了问题。显然它将文件标记为已修改,并且在修改后使用文件上的FileReader时遇到问题。但是有办法解决它

有一种方法可以用来读取文件夹的内容。通过拖放或目录文件输入中的文件夹选择获得目录entery后,您可以反复循环遍历每个文件以查看是否有更改。

由于某种原因,由于沙盒限制而无法在SO中运行所以我创建了jsfiddle

function traverseFileTree(entery, path) {
  path = path || ""

  if (entery.isFile) {
    // Get file
    entery.file(file => {
        setInterval(() => {
          entery.file(file => {
            console.log(file.lastModifiedDate, file.size, path)
          })
        }, 1000)
    })
  } else if (entery.isDirectory) {
    // Get folder contents
    var dirReader = entery.createReader()
    dirReader.readEntries(entries => {
      for (let entery of entries) {
        traverseFileTree(entery, path + entery.name + '/')
      }
    }, console.error)
  }
}

var dropzone = document.getElementById('dropzone')

dropzone.addEventListener("drop", function(event) {
  event.preventDefault()

  const items = event.dataTransfer.items

  for (item of items) {
    // webkitGetAsEntry is where the magic happens
    const entery = item.webkitGetAsEntry()

    if (entery) {
      traverseFileTree(entery)
    }
  }
}, false)

// Required for drop event to event do what we want
dropzone.ondragover = event => {
  event.preventDefault()
  return false
}
#dropzone{
  background: black;
  height: 30px;
  color: white;
  padding: 10px;
}
<div id="dropzone">
  drop a directory here
</div>