Chrome App FileReader

936 views Asked by At

I'm trying to make use of the file system API in a Chrome App. I've tried all the sample code I can find and can't get a simple text file to read. I'm logging almost every step, and what seems to happen (or not happen) is everything stops the first time I reference a file reader object. It creates just fine, because I can log the .readyState, but after that I can't seem to even set an onload()event or execute a .readAsText().

Here's what I'm calling from a button:

 function clickButton(){

  chrome.fileSystem.chooseEntry({type: 'openFile', acceptsMultiple: false}, function(FileEntry){
    if(chrome.runtime.lastError) {console.warn("Warning: " + chrome.runtime.lastError.message);}
    else{
      console.log(FileEntry);
      var thing = new FileReader();
      console.log(thing.readyState);
      thing.onloadstart(function(){
        console.log("Started loading " & FileEntry);
      });
      console.log("added onloadstart");
      console.log(thing.readyState);
      console.log(thing);
      thing.readAsText(FileEntry);
      console.log(thing.readyState);
      console.log(thing.result);
    }
  });

  document.getElementById("status").innerHTML = "I did something";
 }

I did read somewhere that Chrome doesn't allow access to local files, but the chrome apps seem to be different. At least, the documentation seems to suggest that.

The only thing I end up with in my console is the FileEntry object.

https://developer.chrome.com/apps/app_storage#filesystem

I've used the example code right from the above link and still can't get it right. Anyone else have this issue or know what I'm doing wrong?

4

There are 4 answers

1
Daniel Herr On BEST ANSWER

There is a difference between a FileEntry and a File. You need to call FileEntry's .file() method. So, replace

thing.readAsText(FileEntry);

with

FileEntry.file(function(File) {
  thing.readAsText(File)
})

https://developer.mozilla.org/en-US/docs/Web/API/FileEntry#File

1
Jaffer Wilson On

Try this code...

<!doctype html>
<html>
<script>
function handle_files(files) {
  for (i = 0; i < files.length; i++) {
    file = files[i]
    console.log(file)
    var reader = new FileReader()
    ret = []
    reader.onload = function(e) {
      console.log(e.target.result)
    }
    reader.onerror = function(stuff) {
      console.log("error", stuff)
      console.log (stuff.getMessage())
    }
    reader.readAsText(file) //readAsdataURL
  }

}
</script>
<body>
FileReader that works!
<input type="file" multiple onchange="handle_files(this.files)">
</body>
</html>
0
Andrew Shepherd On

I've written a function to extract text from a file.

  function getFileEntryText(fileEntry) {
    return new Promise(function (resolve, reject) {
      fileEntry.file(function (file) {
        var fileReader = new FileReader();
        fileReader.onload = function (text) {
          resolve(fileReader.result);
        };
        fileReader.onerror = function () {
          reject(fileReader.error);
        };
        fileReader.readAsText(file);
      });
    });
  }

You can invoke this method like so:

getFileEntryText(fileEntry).then(function(text) {
      // Process the file text here
}, function(error) {
   // Handle the file error here
});

One thing I'm grappling with when working with the FileSystem is that every call is asynchronous. Having multiple levels of nested callbacks can make for code that's hard to read. I'm currently working around this by converting everything I can to a Promise.

0
Nerd1 On

for anyone who is interested, here's my final (working) code, complete with all the console.log()'s I needed to follow all those callbacks.

var chosenEntry = null;

 function clickButton(){
    console.log("Button clicked");
    var accepts = [{
      mimeTypes: ['text/*'],
      extensions: ['js', 'css', 'txt', 'html', 'xml', 'tsv', 'csv', 'rtf']
    }];
    chrome.fileSystem.chooseEntry({type: 'openFile', accepts: accepts}, function(theEntry) {
      if (!theEntry) {
        output.textContent = 'No file selected.';
        return;
      }
      // use local storage to retain access to this file
      chrome.storage.local.set({'chosenFile': chrome.fileSystem.retainEntry(theEntry)});
      console.log("local data set.  calling loadFileEntry");
      loadFileEntry(theEntry);
      console.log("loadFileEntry called, returned to clickButton()");
    });
 }

 function loadFileEntry(_chosenEntry) {
  console.log("entered loadFileEntry()");
  chosenEntry = _chosenEntry;
  chosenEntry.file(function(file) {
    readAsText(chosenEntry, function(result) {
      console.log("running callback in readAsText");
      document.getElementById('text').innerHTML = result;
      console.log("I just tried to update textarea.innerHTML");
    });
  });
  console.log("added function to chosenEntry.file()");
 }

function readAsText(fileEntry, callback) {
  console.log("readAsText called");
  fileEntry.file(function(file) {
    var reader = new FileReader();
    console.log("Created reader as FileReader");
    reader.onload = function(e) {
      console.log("called reader.onload function");
      callback(e.target.result);
    };
    console.log("calling reader.readAsText");
    reader.readAsText(file);
  });
}