If one searches File on caniuse.com and expands show all, it's evident that older browsers (e.g. Android) have the following issues:
Does not have FileReader support.
Does not support the File constructor.
I want to understand what the first statement means in practice.
For instance, I'm receiving a file via an HTML input element like so:
var img_file = e.target.files[0];
Note that img_file is an object of type File.
Next, I'm reading the first few bytes of the file using a FileReader() object, and then determining the mime type:
var reader = new FileReader();
reader.onload = validate_file;//validates the file's mime type
reader.readAsArrayBuffer(img_file.slice(0,4));
Does "Does not have FileReader support" imply that the statements above will give an error? If so, are there any workarounds for unsupportive browsers? I'd love to see an illustrative example around such workarounds (if they exist).
Note: Please use pure JS for the scope of this question, and sans any 3rd party libraries.
Related
The codes (angular 2) below returns different results in Chrome and Firefox after the selected file has been modified content:
isExistedFiles(funcCallBack: any) {
try {
const r = new FileReader();
r.onerror = function (e: any) {
funcCallBack(0);
};
r.onload = function (e: any) {
funcCallBack(1);
};
r.readAsText(this.files);
} catch (e) {
funcCallBack(0);
}
}
Result:
-Firefox: FileReader { readyState: 2, result: null, error: DOMException,...
-Chrome: FileReader {readyState: 2, result: "PK ....", error: null,...
Why it happens? And how to fix it?
They indeed have different behaviors with regard to Files that are modified on disk after user selection, and IIRC this behavior even changes on different OSes.
(This answer is only based on observations made on macOS system it might not match yours)
Chrome does updates the File's metadata at access.
Firefox doesn't update these metadata at access, so if the file size when you try to read it is smaller than what it was when the user selected it, then the FileReader will throw an Error.
This is because, since it uses the old metadata, it has been asked to read non-existant data.
To make it more visual, let's take the File's content at user selection:
abcdefghijklmnopqrstuvwxyz
When Firefox will request the File's metadata, the OS will tell it size: 26.
Now, let's change this File's content to
abc
If we try to read this File through a FileReader, FF will use the metadata the OS gave to it (size:26). So it will try to read until the 26th byte of this file.
Obviously, this doesn't work... And that's your why.
So now, "how to fix it"?
Well, that depends what you mean by this... If you want to have Chrome's behavior on Firefox, you could fetch the File on disk by using a blobURI adn AJAX, actually loading it from disk to memory, and hence, with new metadata.
But beware this won't work in Safari, which does itself create a blobURI from selected Files, but which won't allow us to fetch it as a fresh one on the disk if it has been changed...
An other, uglier workaround taht would give you only the File "as it was" when user selected it, would be to create a copy of it in memory (I think FileReader.readAsArrayBuffer is the most cross-browser way to do it). But if your user did modify it, they might be disappointed to see their changes are not reflected.
So maybe the best solution, is to simply handle the error, and provide a message to your user explaining them that it's bad to modify a file that has already been selected, and offer them to select it again.
Ps: Highly related
I've got a web page which needs to be able to load files into the DOM from the local machine on which the browser is running. I've found that this is very easy to do using the HTML 5 File API.
I can just do:
var reader = new FileReader();
reader.onload = function (fileContents) { ... load contents to a div ... }
reader.readAsText(f) //where f is an HTML5 File object
Annoyingly, I need this to work in IE7, and also some earlier versions of Firefox which don't support the API. Is there any easy way to load a local file into the DOM in older browsers?
Many thanks!
No, you cannot do that in older browsers. FileReader (any file system access really) is a new HTML5 feature which is not supported in older browsers.
Your best option in an older browser is either:
A Silverlight, Flash or Java app (or similar) that runs on the client-side and has local file system access.
Having the user upload files using the <input type="file"> element, and do your processing server-side.
Further to the other answers here, it does appear that there's no consistent way of doing this client-side (other than Flash) for older browsers.
For IE7/8 however, I've managed to hack something together using ActiveX.
var filePath = f:\oo.txt;
var fso = new ActiveXObject("Scripting.FileSystemObject");
var textStream = fso.OpenTextFile(filePath);
var fileData = file.ReadAll();
I can then pass this to the same function as reader.onload in the question above. Obviously this is a bad, hacky solution, and liable to be blocked by some security policies - it does at least work for IE7 though!
Looks like you can do that through Flash. Flash alternative for FileReader HTML 5 API
if (window.ActiveXObject) {
try {
var fso = new ActiveXObject("Scripting.FileSystemObject");
fso.CopyFile("C:\\Program Files\\GM4IE\\scripts\\source.txt","C:\\Program Files\\GM4IE\\scripts\\target.txt", 1);
fso = null;
}
catch (e) {
alert (e.message);
}
}
I am getting error :
"Automation server can not create object" on the line where I am creating ActiveXObject instance.
I understand that it's considered very bad to access hard-drive data using javascript but I just need it.
I am using IE8 , Greasemonkey4IE to run my javascript.
Thank you,
Mohit
******************************
function WriteFile()
{
var fso = new ActiveXObject("Scripting.FileSystemObject");
fso.CopyFile("C:\\source.txt","C:\\target.txt", 1);
}
I've put the above code inside a simple HTML page and it worked perfect.
http://www.c-point.com/JavaScript/articles/file_access_with_JavaScript.htm
You can find the similar code on above mentioned location.
I modified it a bit, tough.
But when I am trying to run it through GreaseMonkey4IE it simply spitting the same error I specified earlier.
I did it guys, but thanks a lot for your quick and helpful replies.
All I did is :
Go to Tools > Internet options > Security > Custom Level
Under the ActiveX controls and plug-ins, select Enable for Initializing and Script ActiveX controls not marked as safe.
Using native JavaScript, no, it is not generally possible to access a local file. Using plugins and extensions like ActiveX, Flash, or Java you can get around this rule, generally with some difficulty.
For some browser and OS specific exceptions to this general rule, you might want to have a look here:
Local file access with javascript
Note that as of late 2012, the FileReader API has been supported in all major browsers and provides a native JavaScript mechanism for accessing local files that the user nominates (via an input element or by dropping them into the browser).
This still cannot be used to access an arbitrary file by name/path as in the examples in the original question.
HTML5 File API has multiple ways to access local files.
window.requestFileSystem allows you to request access to the filesystem. Browser support is very poor on this (Chrome only).
FileReader is the HTML5 FileReader API that allows you to programatically read files that users select through a <input type='file' /> Browser support is better on this.
You should use fallbacks like flash and POST to a server for full file access.
Generally reading arbitary files is considered "cheating the browser" so I you'll either have to use secure HTML5, ActiveX or Flash. All 3 of those require user permissions.
After some research I have found:
var fso = new ActiveXObject("Scripting.FileSystemObject");
//This line will create a xml file on local disk, C drive
fh = fso.CreateTextFile( "C:\\fileName.xml", true);
fh.WriteLine("this is going to be written in fileName.xml");
This is how we can do it.There are other methods also.
Accessing local file system is very bad thing to do but yes we can do it.
Automation server can not create object
To get rid of this error go to Tools → Internet Options → Security → select Internet icon → click Custom level → select Enable for Initialize and script ActiveX controls not marked as safe for scripting.
I have not tested this on any other berowser except IE8, but I am sure it will work.
Is there a JavaScript library that allows to save strings as txt files, and works cross-browser?
In the past, I have been using Downloadify, but I am looking at another option for a couple reasons:
I hope to find a pure JavaScript solution, without the need for Flash
it seems that Downloadify is not updated anymore
(no update in the past 18 months)
I am experiencing an issue with Downloadify in IE 9, where strings are cut off
Here is what you need. But it's not cross-browser yet. Works in Google Chrome.
<a download="MyFile.txt"
href="your-data-uri-here"
draggable="true"
class="dragout"
>Download ready</a>
Also Wikipedia has a good article about Data URI
As far as I know, the only way is to use data: URLs to force a download:
var data = "This is a test";
window.location.href = "data:application/x-download;charset=utf-8," + encodeURIComponent(data);
Two catches here:
It won't work in MSIE because its support of data: URLs is very limited (supposedly for security reasons). So you will still need Downloadify there.
You cannot specify a file name, the suggested file name will depend on the browser used. And file type will be "unknown" (you cannot use a known MIME type because the browser won't offer to download the file then).
Bonus reading: there was a W3.org discussion in February 2010 on fixing the second problem: http://lists.w3.org/Archives/Public/uri/2010Feb/thread.html#msg58. However, this doesn't seem to have made it into any specification so far, let alone browser implementations.
FileSaver API is cross-browser compatible
var text = "Hello, world!";
var blob = new Blob([text], {type: "text/plain;charset=utf-8"});
FileSaver.saveAs(blob, "filename.txt");
I want to use SpiderMonkey for driving a test harness (for the in-browser version see here). Now, I tried the following:
var defaultFileName = "all.n3";
var reader = new FileReader();
reader.readAsText(defaultFileName);
reader.onload = fileLoaded;
which fails with the following error:
regression-tests.js:9: ReferenceError: FileReader is not defined
Sorry if this is a dumb question but I did look around here and RTFMd for a bit but wasn't able to figure what to do (import? how?).
Check out help() in the SpiderMonkey shell -- it tells you about a whole bunch of functions that are available in the shell-only version (like snarf, which is our (weirdly) named function to read a file into a string -- not sure the history of that name). It's a different API than is available in the browser, because the shell is supposed to be a minimal JS execution engine.
FileReader is an XUL component. XUL components aren't available the standalone version of SpiderMonkey - they're provided by the browser.