Reputation: 15
I'm working on a project that requires submitting files through a web page. Although it's not necessary, it's convenient for the user to be able to edit the file after already having selected it. However, I ran into the problem that reading the FileReader returns null after making changes and then saving them. My fairly straightforward debugging code is below.
<html>
<head>
</head>
<body>
<input type="file" id="file" value>
<button id="sub">Submit</button>
</body>
<script>
document.getElementById("sub").addEventListener("click", function() {
var reader = new FileReader();
reader.addEventListener('loadend', function() {
var src_code = this.result;
console.log(src_code);
});
if (document.getElementById("file").files.length == 0) {
//empty
alert("empty");
}
else {
console.log(document.getElementById("file").files[0]);
reader.readAsText(document.getElementById("file").files[0]);
}
});
</script>
</html>
I read another question here that claims FileReader is at fault for this but, unfortunately, I absolutely need the text within the file and the answer did not provide an alternative.
Is there a way to get the text from a file that lets the user update the file after selecting it?
Upvotes: 0
Views: 1706
Reputation: 136986
No, there is no reliable way.
When selecting a file from an <input type="file"> the browser gets a pointer to the file on disk along with some metadata provided by the OS. Luckily, it doesn't save the file's data in memory (would be quite hard to upload multi-GB files otherwise), and it doesn't lock the file on disk either.
So the user can indeed edit the file on disk, and they can even remove it from the disk. However, most browsers will use the metadata provided by the OS at the moment of picking it in order to read the file through a FileReader.
This means that if your file was 120KB when picked, then edited to make it a 100KB file, the browser will ask for data that doesn't exist anymore, and the reader will crash.
You can of course force the browser to store the full data in memory at the moment of picking it, e.g
blob = new Blob( [ await file.arrayBuffer() ], { type: file.type } );
here blob
holds in memory the data that file
was pointing to at the moment it's been called.
But blob
is not connected anymore with the file on disk, so if your user does edit the file on disk, blob
won't be changed.
Note that Firefox will actually be able to handle edited files through the Blob methods (arrayBuffer()
and text()
) at least on macOS (I guess OS matters here), but their FileReader will still fire an Error. Chrome just throws in both cases.
In the same way, fetching the file through XHR
or fetch
will throw in Chrome (but not in FF if the file only has been edited and still exists).
Upvotes: 5