Javascript, FileReader vs XMLHttpRequest for reading a local file? - javascript

I'm trying to read a local file with javascript and a Google Chrome App (it may not be possible through Chrome I think), but I can't see what's the latest approach to the problem.
I can read it with the following code:
obj.read = function() {
return new Promise(function(resolve){
var xmlhttp = new XMLHttpRequest();
var file_path = 'file_name.xml';
xmlhttp.open('GET', file_path, true);
xmlhttp.send(null);
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
let xml = xmlhttp.responseText;
var parser = new DOMParser();
var xmlDoc = parser.parseFromString(xml, "text/xml");
console.log(xml);
console.log(xmlDoc);
resolve(xmlDoc);
}
}
});
};
But it is like I should be using something like
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
console.log(e.target.result);
};
})(file_path);
var file_path = 'file_name.xml';
var file_parts = [
new Blob(['you construct a file...'],{type: 'text/plain'}),
'Same way as you do with blob',
new Uint16Array([33])
];
var file = new File(file_parts, file_path);
reader.readAsText(file);
(copied from https://stackoverflow.com/a/24495213/826815)
(I'm having a hard time finding literature on this topic)
So, what's the way to do it?

The first approach (XMLHttpRequest for a file in the package) is perfectly valid and likely to be easier if all you need is the whole file.
What you call a "second approach" is lifted from a question about instantiating a File object, not reading an actual file. This would not allow you to read an existing file, just create a "virtual" file that can be used in DOM forms.
There's the whole HTML FileSystem API, which is not implemented anywhere but Chrome and as such documentation is scarce and fraught with big scary red warnings. You can actually use it for the purpose you state - reading App's own files - by starting with chrome.runtime.getPackageDirectoryEntry, but that's probably overkill in your particular case and again, you'll have a hard time finding examples of doing so.
I can think of only two reasons to disturb the slumber of the beast that is FileSystem API for App's own files:
You don't know, at runtime, what files are included. Then you can use it to list files. Rare, but possible.
You need a more fine-grained access than "get me the whole thing", for example you only need a chunk of a large file.
Note that FileSystem API is primarily used in Chrome for chrome.fileSystem Apps API. Considering that Chrome is going to support Chrome Apps on Chrome OS for a while, it's likely to stay, despite being non-standard.
Surviving documentation:
The above-mentioned HTML5Rocks article: Exploring the FileSystem APIs
Last public standards document: File API: Directories and System
Actual standards document on File API (that your "second example" is covered by): File API

Related

How to post blob and string with XMLHttpRequest javascript and PHP [duplicate]

I've seen many partial answers to this here and elsewhere, but I am very much a novice coder and am hoping for a thorough solution. I have been able to set up recording audio from a laptop mic in Chrome Canary (v. 29.x) and can, using recorder.js, relatively easily set up recording a .wav file and saving that locally, a la:
http://webaudiodemos.appspot.com/AudioRecorder/index.html
But I need to be able to save the file onto a Linux server I have running. It's the actual sending of the blob recorded data to the server and saving it out as a .wav file that's catching me up. I don't have the requisite PHP and/or AJAX knowledge about how to save the blob to a URL and to deal, as I have been given to understand, with binaries on Linux that make saving that .wav file challenging indeed. I'd greatly welcome any pointers in the right direction.
Client side JavaScript function to upload the WAV blob:
function upload(blob) {
var xhr=new XMLHttpRequest();
xhr.onload=function(e) {
if(this.readyState === 4) {
console.log("Server returned: ",e.target.responseText);
}
};
var fd=new FormData();
fd.append("that_random_filename.wav",blob);
xhr.open("POST","<url>",true);
xhr.send(fd);
}
PHP file upload_wav.php:
<?php
// get the temporary name that PHP gave to the uploaded file
$tmp_filename=$_FILES["that_random_filename.wav"]["tmp_name"];
// rename the temporary file (because PHP deletes the file as soon as it's done with it)
rename($tmp_filename,"/tmp/uploaded_audio.wav");
?>
after which you can play the file /tmp/uploaded_audio.wav.
But remember! /tmp/uploaded_audio.wav was created by the user www-data, and (by PHP default) is not readable by the user. To automate adding the appropriate permissions, append the line
chmod("/tmp/uploaded_audio.wav",0755);
to the end of the PHP (before the PHP end tag ?>).
Hope this helps.
Easiest way, if you just want to hack that code, is go in to recorderWorker.js, and hack the exportWAV() function to something like this:
function exportWAV(type){
var bufferL = mergeBuffers(recBuffersL, recLength);
var bufferR = mergeBuffers(recBuffersR, recLength);
var interleaved = interleave(bufferL, bufferR);
var dataview = encodeWAV(interleaved);
var audioBlob = new Blob([dataview], { type: type });
var xhr=new XMLHttpRequest();
xhr.onload=function(e) {
if(this.readyState === 4) {
console.log("Server returned: ",e.target.responseText);
}
};
var fd=new FormData();
fd.append("that_random_filename.wav",audioBlob);
xhr.open("POST","<url>",true);
xhr.send(fd);
}
Then that method will save to server from inside the worker thread, rather than pushing it back to the main thread. (The complex Worker-based mechanism in RecorderJS is because a large encode should be done off-thread.)
Really, ideally, you'd just use a MediaRecorder today, and let it do the encoding, but that's a whole 'nother ball of wax.

File manipulations such as Read/Write local files using Javascript without server

I'm just trying on the task, file manipulation system using java script. As I was referred from W3C File API( https://www.w3.org/TR/FileAPI/ ), we can only read local files like
var file = "test.txt";
function readTextFile(file) {
var readFile;
if(window.XMLHttpRequest){
// for new browsers
readFile = new XMLHttpRequest();
}else{
//for old browsers like IE5 or IE6
readFile = new ActiveXObject("Microsoft.XMLHTTP");
}
readFile.open("GET", file, true);
readFile.onreadystatechange = function() {
if(readFile.readyState === 4) {
if(readFile.status === 200 || readFile.status == 0) {
//text will be displayed that read from the file
console.log(readFile.responseText);
}
}
}
readFile.send(null);
}
but it looks there is no options to write on file without server. I was tried to fetch solutions from the websites like http://www.stackoverflow.com/, the study says almost there is no possibilities.
For an example what I got is
from https://gist.github.com/Arahnoid/9925725
It shows error "TypeError: file.open is not a function."
So my question is, Is there any possible to file manipulations(asking only about Write file) for local files without using server-side scripting or is any extensions like available?
We can do file manipulations using server scripting languages such as PHP, Node.js.
Thanks in advance.
In your code, it's not reading from the local file (test.txt), it's sending Ajax GET request to server and read file in server side.
To read local file (files that stored in machine where browser is installed), you need to use FileAPI, which is not used in current code.
To write file to local, it's impossible to write it directly using JavaScript. Otherwise, it would be a huge security vulnerability. However, you can generate a URL from File object, and use that URL as the href attribute of <a> tag, so that user can download and "write to local" manually.
Here is a code snippet to read & "write" local file:
var inputElement = document.getElementById("input");
var reader = new FileReader();
var downloadLink = document.getElementById('downloadLink');
reader.onloadend = function(){
console.log(reader.result);
}
inputElement.addEventListener("change", handleFiles, false);
function handleFiles() {
var fileSelected = this.files[0]; /* now you can work with the file list */
reader.readAsBinaryString(fileSelected);
downloadLink.href = window.URL.createObjectURL(fileSelected);
}
<input type="file" id="input">
<a id="downloadLink" download>Download</a>

Large blob file in Javascript

I have an XHR object that downloads 1GB file.
function getFile(callback)
{
var xhr = new XMLHttpRequest();
xhr.onload = function () {
if (xhr.status == 200) {
callback.apply(xhr);
}else{
console.log("Request error: " + xhr.statusText);
}
};
xhr.open('GET', 'download', true);
xhr.onprogress = updateProgress;
xhr.responseType = "arraybuffer";
xhr.send();
}
But the File API can't load all that into memory even from a worker
it throws out of memory...
btn.addEventListener('click', function() {
getFile(function() {
var worker = new Worker("js/saving.worker.js");
worker.onmessage = function(e) {
saveAs(e.data); // FileSaver.js it creates URL from blob... but its too large
};
worker.postMessage(this.response);
});
});
Web Worker
onmessage = function (e) {
var view = new DataView(e.data, 0);
var file = new File([view], 'file.zip', {type: "application/zip"});
postMessage('file');
};
I'm not trying to compress the file, this file is already compressed from server.
I thought storing it first on indexedDB but i i'll have to load blob or file anyway, even if i do request by range bytes, soon or late i will have to build this giant blob..
I want to create blob: url and send it to user after been downloaded by browser
I'll use FileSystem API for Google Chrome, but i want make something for firefox, i looked into File Handle Api but nothing...
Do i have to build an extension for firefox, in order to do the same thing as FileSystem does for google chrome?
Ubuntu 32 bits
Loading 1gb+ with ajax isn't convenient just for monitoring download progress and filling up the memory.
Instead I would just send the file with a Content-Disposition header to save the file.
There are however ways to go around it to monitor the progress. Option one is to have a second websocket that signals how much you have downloaded while you are downloading normally with a get request. the other option will be described later in the bottom
I know you talked about using Blinks sandboxed filesystem in the conversation. but it has some drawbacks. It may need permission if using persistent storage. It only allows 20% of the available disk that are left. And if chrome needs to free some space then it will throw away any others domains temporary storage that was last used for the most recent file. Beside it doesn't work in private mode.
Not to mention that it has been dropping support for it and may never end up in other browsers - but they will most likely not remove it since many sites still depend on it
The only way to process this large file is with streams. That is why I have created a StreamSaver. This is only going to work in Blink (chrome & opera) ATM but it will eventually be supported by other browsers with the whatwg spec to back it up as a standard.
fetch(url).then(res => {
// One idea is to get the filename from Content-Disposition header...
const size = ~~res.headers.get('Content-Length')
const fileStream = streamSaver.createWriteStream('filename.zip', size)
const writeStream = fileStream.getWriter()
// Later you will be able to just simply do
// res.body.pipeTo(fileStream)
// instead of pumping
const reader = res.body.getReader()
const pump = () => reader.read()
.then(({ value, done }) => {
// here you know how large the value (chunk) is and you can
// figure out the download speed/progress when comparing it to the size
return done
? writeStream.close()
: writeStream.write(value).then(pump)
)
// Start the reader
pump().then(() =>
console.log('Closed the stream, Done writing')
)
})
This will not take up any memory
I have a theory that is if you split the file into chunks and store them in the indexedDB and then later merge them together it will work
A blob isn't made of data... it's more like pointers to where a file can be read from
Meaning if you store them in indexedDB and then do something like this (using FileSaver or alternative)
finalBlob = new Blob([blob_A_fromDB, blob_B_fromDB])
saveAs(finalBlob, 'filename.zip')
But i can't confirm this since i haven't tested it, would be good if someone else could
Blob is cool until you want to download a large file, there is a 600MB limit(chrome) for blob since it stores everything in memory.

Javascript new File() gem file size

I have the following file structure:
test.html
test.json
And the following JS function:
function get_file(){
var app_path = app.activeDocument.path,
file = new File(app_path + '/test.json');
console.log(file);
}
How can I make the function log the file's content?
I'm not sure if everything you can do in the browsers environment translates to everything you can do in photoshops environment. But you should look at a few things.
Doing This in the Browser
The File object.
https://developer.mozilla.org/en-US/docs/Web/API/File
Notable that it extends the Blob object.
https://developer.mozilla.org/en-US/docs/Web/API/Blob
Which if you researched you would find it can be read using the FileReader.
https://developer.mozilla.org/en-US/docs/Web/API/FileReader
So this would work in the browser but may/may-not work in the photoshop scripting set.
function get_file(){
var app_path = app.activeDocument.path,
file = new File(app_path + '/test.json');
var reader = new FileReader();
reader.onloadend = function() {
console.log(reader.result);
}
reader.readAsText(file);
}
This is asynchronous so you may need to use a callback depending on what you're trying to do with this. You won't be able to return the string from inside the reader.onloadend event.
Doing This in Photoshop
Take a look at their scripting references. Specifically the javascript reference.
All Resources: http://www.adobe.com/devnet/photoshop/scripting.html
Javascript PDF: http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/photoshop/pdfs/photoshop-cc-javascript-ref-2015.pdf
It looks like they don't have the FileReader but instead the File object can be used to read content. The File API begins on page 109 but it's empty! The documentation is a bit pathetic so I can see why you'd have trouble finding this. With some searching I found someone doing this in 2012 (but I don't know if it will still work- worth a shot)
var b = new File("c:\test.txt");
b.open('r');
var str = "";
while(!b.eof) {
str += b.readln();
}
b.close();
alert(str);
Let me know if that works.

Access JSON property value before loading the contents of the file

I have an angularjs project which retrieves JSON files from a server and uses the contents to display the data in the screen.
I'm using a service to load the data, and this service calls the server for a new JSON file every 2 seconds (I removed that from the code below for simplicity).
var data = $resource(:file.json', {}, {
query: {method: 'GET', params: {file: '#file'}}
});
this.load = function(file, myFunction) {
data.query({file:file}, function(data) {
myFunction(data);
}
}
Now, these files can be really big and sometimes there's no need to process the file because there are no changes from the previous one received. I have a property in the JSON file with the version number, and I should not process the file unless that version number is higher than the one in the previous file.
I can do that by calling the query service, which loads the file contents into a js object and then check the version, if the file is really big it might take a while to load it. Is there a way to access that property value (version) ONLY and then, depending on it, load the file into a js object?
EDIT: The thing that I'm guessing is that loading a 1MB JSON file to check a version number inside it might take a while (or maybe no and that $resource action is really fast, anyone knows?), but I'm not really sure that it can be done any other way, as I'm checking a specific property inside the file.
Many thanks in advance.
HTML5 and Javascript now provides a File API which can be used to read the file line by line. You can find information regarding this feature here:
http://www.html5rocks.com/en/tutorials/file/dndfiles/
This will slice the full file into string and take just the first line(asuming the version is in there)
data.substr(0, data.indexOf("\n"));
--
Bonus:
Also in this answer you will find out how to read the first line of a file:
https://stackoverflow.com/a/12227851/2552259
var XHR = new XMLHttpRequest();
XHR.open("GET", "http://hunpony.hu/today/changelog-en.txt", true);
XHR.send();
XHR.onload = function (){
console.log( XHR.responseText.slice(0, XHR.responseText.indexOf("\n")) );
};
Another question with the same topic:
https://stackoverflow.com/a/6861246/2552259
var txtFile = new XMLHttpRequest();
txtFile.open("GET", "http://website.com/file.txt", true);
txtFile.onreadystatechange = function()
{
if (txtFile.readyState === 4) { // document is ready to parse.
if (txtFile.status === 200) { // file is found
allText = txtFile.responseText;
lines = txtFile.responseText.split("\n");
}
}
}
txtFile.send(null);
Do you have access to the json files?
I'm not sure how you generate your json files but you could try adding the version number in the filename and check if a newer filename exists. I have not tested this but maybe it's worth a try.

Categories

Resources