Search code examples
javascriptfilegoogle-chromelocaltext-parsing

Constantly read local file with JS?


I've been looking all over the place but I can't find a solution to reading a local text file (in the same folder as my js and html files) repeatedly that works with Chrome.

I need to constantly read the file for updates, which another program updates automatically, I don't know how. It's just a regular text.txt file.

I've read a lot of questions/answers on here about it, but so far I've found nothing. Can anyone help?

edit: I meant without node as well, just vanilla JS.


Solution

  • You can enable XmlHttpRequest for local files by starting Chrome with it's security features disabled. This is not an ideal solution but it is the only way to automatically do what you want without running some kind of server. Using Node to watch the file for changes and pushing the data over a WebSocket to the browser would be the proper way to handle this.

    Alternatively you could use the FileReader API to open this local file but you need to select it manually through an <input type="file"> element first.

    function readInputFile(event) {
      let file = event.target.files[0];
    
      if (!file) {
        return;
      }
      
      let reader = new FileReader();
      
      reader.addEventListener('load', event => {
        let content = event.target.result;
        alert(content);
      });
      
      reader.readAsText(file);
    }
    
    document.getElementById('datafile').addEventListener('change', readInputFile, false);
    <input type="file" id="datafile">

    Edit:

    It's 2022 now and we have another way to accomplish this using the File System Access API. It's currently not available in Firefox but this method could be useful if you're only targeting Chromium based browsers (for example: in an Electron app). Note that this feature is only available in secure contexts such as from localhost or over https.

    <!DOCTYPE html>
    <title> File System Access API Test </title>
    <button id="pick"> Pick File </button>
    <button id="stop" disabled> Stop Watching </button>
    <script>
      const pickButton = document.querySelector('button#pick');
      const stopButton = document.querySelector('button#stop');
    
      let selected, i;
      let pollRate = 15; // seconds
    
      pickButton.addEventListener('click', accessFile);
      stopButton.addEventListener('click', stopWatching);
    
      async function accessFile() {
        stopWatching();
        
        let [fileHandle] = await window.showOpenFilePicker();
        
        if (fileHandle) {
          let f = await fileHandle.getFile();
          if (!f) { console.log('failed accessing file'); return ; }
          selected = { handle : fileHandle, file : f };
          console.log('selected', f.name);
          readFile(f);
          startWatching();
        } else {
          console.log('no file selected');
        }
      }
      
      async function checkFile() {
        if (!selected) { return; }
        let f = await selected.handle.getFile();
        if (f.lastModified > selected.file.lastModified) {
          console.log(selected.file.name, 'was updated');
          selected.file = f;
          readFile(f);
        } else {
          console.log(selected.file.name, 'had no changes');
        }
      }
      
      function readFile(f) {
        let reader = new FileReader();  
        reader.addEventListener('load', event => {
          console.log(event.target.result);
        }); reader.readAsText(f);
      }
      
      function startWatching() {
        if (i) { clearInterval(i); }
        stopButton.disabled = false;
        i = setInterval(async ts => {
          if (!selected) { return; }
          checkFile();
        }, pollRate * 1000);
      }
      
      function stopWatching() {
        clearInterval(i);
        i = null;
        selected = null;
        stopButton.disabled = true;
      }
    </script>