0

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.

supafiya
  • 137
  • 2
  • 9
  • 1
    So keep fetching it with Ajax. – epascarello Dec 13 '18 at 20:11
  • 1
    Please insert your code to your question! Without code it's hard to help you. – FZs Dec 13 '18 at 20:13
  • What **exactly** have you tried? How are you reading this file **now**? Was [this question](https://stackoverflow.com/q/14446447/691711) one of the *"lot of questions/answers on here"* that you read? What about it didn't work? – zero298 Dec 13 '18 at 20:38
  • @zero298 Yes I have read that question, it didn't work because Chrome won't allow you to do XMLHttp requests to local files. I've tried the fetch api too and that doesn't work on chrome either, I've tried FileReader but that still won't work. – supafiya Dec 13 '18 at 21:18

2 Answers2

2

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>
Besworks
  • 4,123
  • 1
  • 18
  • 34
  • 1
    I tested this, and it actually doesn't need to be re-selected every time the file changes. I tested it with a setInterval to read the file every 5 seconds, and It showed the changes. I think this could work, Thank you. – supafiya Dec 13 '18 at 22:05
  • Interesting, it would seem that as long as you don't reset the input field you can re-read the file indefinitely. Good to know. – Besworks Dec 13 '18 at 22:20
  • In Chrome 83, I can read the file again but its content does not change and the onload event does not fire. It seems that Chrome is optimizing away subsequent reads. – GaryBishop Jul 13 '20 at 13:53
0

I think you might be confused what a 'local' file is in this context.

A local file will be loaded with a url such as file://, or selected from a file input in a form.

A file next to your .html and .css is not a local file, it's a hosted file on your web server what you're using to host the .html. You would be referring to it with a relative path to your domain, such as '/file.css'

Node would have more options, seeing that it can read and access local files synchronously with the build in fs ( file system ) library.

What you'll need to do is treat your file like any other on the internet, and download it the same way. Then, download it again later when you need to check for updates. repeat.

Steven Stark
  • 1,249
  • 11
  • 19
  • I know what local files are, and I'm not hosting it anywhere. I'm not using node, I'm simply opening the html file and loading javascript. My main post says that the file I'm reading is updated through another program, so all I want to do is read that file constantly for changes. – supafiya Dec 13 '18 at 21:20