'Simulate' file download in HTML5 web app - javascript

Say I have a webapp which executes in its entirety on the client-side. Its purpose is to act as a file conversion utility, for example converting a user's local stored word document into a PDF.
So with the user's permission, the app can read a specified local file and process it, in memory, into PDF format.
How can I get the user to 'download' the result? since the data is held in the browser's memory anyway, I do not wish to upload it to some server.
[edit]
No flash based solutions
Expected file sizes to be up to 15mb

The solution for my case will be to use the HTML5 FileSaver API.
Perhaps this question should just be closed as it is effectively a duplicate of
Using HTML5/Javascript to generate and save a file
Thanks to aefxx

Related

Save CSV file as a physical file on client machine using Vanilla JavaScript [duplicate]

I have a web application that receives a simple text file, but I need this file to be downloaded to a specific path. Meaning, when the application receives a text file, it will always be downloaded to a specific folder (for example, to C:\MyFolder). If it isn't possible, then I need to copy the file from where user has chosen to my folder.
This application is based on JavaScript.
JavaScript cannot exert any control over my (the visitor's) local filesystem. I remain in complete control of where my downloaded files go, what they are named, and indeed whether I even want to download them in the first place.
Sorry, but the best you can do is inform your users where to put the file you're offering for download. You cannot use JavaScript to choose the destination yourself.
You should be able to do this using a Java applet assuming that you have signed it. The user would be asked to allow your code to run and if allowed, you could do whatever you want: Including downloading a file to a specific location.

Is it possible to read an already existing file using FileReader?

I'm trying to read the contents of a text file that I have stored on my (the host's) computer. When I encountered Javascript's FileReader I thought it was the perfect tool for the job. However, every example or question I see online shows how to use it to read files that are being uploaded from the user's computer (and thus they can use the event target to point toward which file they want to read) or they use AJAX (well, at least the XMLHttpRequest object) to read their own files.
So is it possible to read from local (to the host) files using FileReader? As I am researching this question it is making me wonder if I am going about this all wrong, but is the only way to use information from a text file on a webpage through AJAX? That seems wrong, it seems like there must be an easier way.
A FileReader needs a Blob. Which is an object representing a binary file in memory.
From where this Blob comes from doesn't really matter, but you need to have it the browser's assigned memory so that FileReader can access it. FileReader won't download anything by itself.
So if you are talking about a file stored on your server, then the browser has to download it from there to the computer's memory. As to how this can be achieved, there are many ways the most common being AJAX, as long as the data is downloaded from the server and accessible, at least to build a Blob from it, then FileReader will be happy.
If you are talking about a file stored on the user's disk, then the browser needs to be granted the permission to access it and load it in its memory, this is usualy done using an <input type="file"> element, since for security reasons, browsers don't give access to the user disk otherwise.

File API, Persistent link to a local file

I'm currently working on some web script based on a game (to port a game to the web).
The scripts download data from my web host so the loading is slow (have to download each files : maps, models, textures, ...).
To correct this, I added an option that allow users to select their local game data in their computer (using the File API - drag and drop) to parse content directly from local and avoid downloading multiple megas from the web, the result is incredibly fast.
Here the problem : each time they reload the browser, they have to re-select their files, again and again. It's not user-friendly.
So, is there a way to keep a reference from this game archive to avoid the user to re-do the drag and drop each time ? I know about security concern, just want to know if there is something like a persistent URL.createObjectURL().
Note: the game data is about ~2Go, so it's not possible to store it in the FileSystem API (and I don't want to copy it, it's waste space to copy data when you can just keep a reference to it).
Thank you :)
You have to have an input from the user
It is not possible to access the files on a client's computer without the user confirming it. Once the user chooses a file (You can listen to it with the change event), you can then use the FileReader API for example to read the file.
document.getElementById("input").addEventListener("change", function() {
const fs = new FileReader();
fs.readAsText(this.files[0]);
fs.onloadend = function() {
document.getElementById("output").innerText = fs.result;
}
});
<input id="input" type="file" />
<div id="output"></div>
Using localStorage to store a fraction of your files
You could use the localStorage API to store some of your files, but the capacity is very limited, especially for a project like yours (maximum of 5 to 10 MB on current most popular browsers).
This would make your coding much harder, as you would have to check every time what was stored or not, and load what is not saved.
Caching
By using caching, you basically fall into the same problem as you are with localStorage: each browser has its own maximum capacity.
The advantage of this method is that you do not have to worry about what has been loaded or not, as the browser will do this by itself.
Using Flash
Now if you really do not care at all about security, you could use a Flash plugin to store and load the files, and then use ExternalInterface to load the data in your JavaScript code.
ExternalInterface.call("loaded", filename, data);
// And then in JavaScript:
// function loaded(filename, data)
// ...
You could use SharedObject to save and load your data.
I am not an AS3 expert, please excuse any clumsiness.
A Desktop application?
Last option would be converting and bundling your game into a desktop application, for example by bundling it through electron, and then using for example NeDB, which is currently the suggested tool by electron for persistant storage.
You may want to consider using IndexedDB. It is supported in recent browsers including Chrome, Firefox, and Safari (macOS and iOS). IndexedDB allows you to save Blob, File or ArrayBuffer as values in an IndexedDB object store.
Check this IndexedDB: Store file as File or Blob or ArrayBuffer. What is the best option?.

Using data URIs to prompt the user to save files

I'm writing a web application which allows a user to select a PNG file, write an iTXt chunk to it and then save it back to their local file system. I would use the new FileWriter API to do so but currently only Google Chrome has added support for it.
Since my file is represented in memory as a binary string I use data URIs to prompt the user to save the file as follows:
window.location.href = "data:application/octet-stream;base64," + btoa(blob);
Since the mime-type is application/octet-stream the browser prompts the user to open or save it. However the problem is that the user does not know which type of file it is. So the user has to add the file extension manually.
Currently I alert the user which extension the file needs to be saved with. However this seems like an inelegant solution. Is there a better way to achieve the same result?
If this were HTTP, then you'd either have to set the content disposition to attachment, to get the file saved even if its mime type is known, or to set the file name for an attachment of octet-stream type. Neither of these headers can be emulated using the data: URI, though, so I see no way to open a “Save as…” dialog using such a URI.
Others have asked how to open a save file dialog for a js variable, and judging from the answers there, there appears to be ready-to-use solutions which work as long as the client has Flash installed (and not blocked).
So perhaps you might try severl solutions, starting with the FileWriter you mention, trying a flash-based approach if that isn't available, and falling back to data: URI with an alert message about the file name extension. That way you could probably achieve the best result possible for each client.

JavaScript downloader

I want to allow a web site users to be able to download files from my site, but with the help of a client-side downloader with an ability to continue an interrupted download.
For example, I want to sent a person a file with a size of 30+ Meg. I want the user to have the best downloading experience, so I can't afford him downloading 25 Meg and then getting the download dropped due to the network problems on his side.
Therefore, I want to have a javascript downloader rendered on a download page, that will show the actual client-side file delivery, and when it is downloaded, to give an ability to a user to save the file.
Or is it not possible due to the fact that javascript won't be able to open a save file dialog and save to a file system?
I'm afraid that is not possible with JavaScript and that's why:
To continue downloading from the certain point you should send to the server the position number to start downloading from. And as JavaScript has no access to local file system, you can't get that position.
UPD: it seems that I was too hurrying with the reply.
The file size can be gotten using the HTML5 File API and after getting the file size you can pass it to the server which should support the partial downloading.
But anyway, after downloading another part of the file you should sew two pieces together in some way; standard web browser dialog will only suggest to overwrite the file.
UPD2: to work with files in some Internet Explorers you can use FileSystemObject:
var fso;
fso = new ActiveXObject("Scripting.FileSystemObject");
I'd look into making a plugin or extension. Like those DownloadThemAll extensions for firefox and Google chrome. Another alternative would be to use Flash, either alone or integrating it with javascript like hinted here: http://www.communitymx.com/content/article.cfm?cid=0922A

Categories

Resources