4

is there a way to watch for file changes in the browser?

the workflow would be:

1) the user open the file

2) the webapp write the file

3) a locally installed app read the file and write some changes

4) the webapp read the last change

5) eventually go to step 2 again

This should be done in the browser.

At the moment I have a button that the user have to press multiple times, but:

1) I would prefer this to be done automatically, without clicking 2) Chrome caches the files, so further changes are not read.

What is the best way to do this?

Here's what I'm doing now:

https://codepen.io/muaddibber/pen/OZJgYQ

window.onload = function() {
    var fileInput = document.getElementById('fileInput');
    var fileDisplayArea = document.getElementById('fileDisplayArea');

    fileInput.addEventListener('change', function(e) {
        var file = fileInput.files[0];
        var textType = /text.*/;

        if (file.type.match(textType)) {
            var reader = new FileReader();

            reader.onload = function(e) {
                fileDisplayArea.innerText = reader.result;
            }

            reader.readAsText(file);    
        } else {
            fileDisplayArea.innerText = "File not supported!"
        }
    });
}

I open a file, prova.txt, and it works.

Then I locally edit the file and reopen it: it doesn't change, chrome still shows the old version.

Mascarpone
  • 2,516
  • 4
  • 25
  • 46

2 Answers2

3

For security reasons, Browsers cannot monitor the filesystem for changes to local files.

Generally, when you use a web page or web app to choose a file, it either gets uploaded to the server immediately, or after pressing a 'submit' or 'upload' button, causing a form submission. After that, the work is done. If you wanted the web app to see any subsequent changes to the file, you'd have to manually upload it again, since it's not possible to watch for changes or automatically upload it again. Yes, it's a pain, but if it wasn't done this way, it could be exploited by malicious web scripts to steal users' data.

Even handling this kind of stuff with browser addons is getting increasingly hard, since WebExtensions (used by Chrome and Firefox) don't usually allow access to the filesystem. That's why most addons like Stylish, Stylus, Greasemonkey, Tampermonkey etc. now have their own built-in editors and save their 'files' to the HTML5 LocalStorage as a workaround. You might have to implement a 'live' editor for your web app too if you want continuous updates.

BoffinBrain
  • 6,337
  • 6
  • 33
  • 59
  • On Nov 3, 2017 in Chrome you *could* monitor the file for last-read date, and read changes. I had a [project doing this which worked](https://github.com/darthwalsh/dotNetBytes/commit/5082f5d6ec7be8d3000f308f87d7fa6d133f2dd9#diff-813b01a597fd4a20f401332009f7b8d32d8cadca6ac152956247822c2728d3f7R508), but it doesn't work now. It never worked in Firefox, though. – Carl Walsh Oct 14 '21 at 19:17
2

There is a way in that you can use to read the content of a folder. Once you have the directory entery from a drag and drop or a folder selection from a directory-file input you can loop over each file again and again to see if something has changed. This means you have no knowing if something has changed... so you need to make that logic yourself effectively checking if the lastModifiedDate has changed or the file size are not the same

Here is a example that will recursively read all the files in every folder and look for a file that ends with .log. If it find a such file it will read that same folder every 1000ms and echo the hole content of it.

If you then change the file (adding a row or change something) it will echo the new content

for some reason it didn't work in SO due to sandboxing restriction so i created a jsfiddle also

function traverseFileTree(entery, path) {
  path = path || ""
  console.log('entery', entery)
  if (entery.isFile) {
    // Get file
    entery.file(file => {
      console.log("File:", path + file.name)
      if (file.name.includes('.log')) {
        setInterval(() => {
          entery.file(file => {
            file.text().then(console.log)
          })
        }, 1000)
      }
    })
  } else if (entery.isDirectory) {
    // Get folder contents
    var dirReader = entery.createReader()
    dirReader.readEntries(entries => {
      console.log('entries', entries)
      for (let entery of entries) {
        traverseFileTree(entery, path + entery.name + '/')
      }
    })
  }
}

var dropzone = document.getElementById('dropzone')

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

  const items = event.dataTransfer.items
  console.log(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>
Endless
  • 34,080
  • 13
  • 108
  • 131