Reading a file that changes using FileReader - javascript

I have an application that generates JSON-based documents. For complicated reasons, the output of that application is often imperfect and needs minor manual corrections. We wrote a validator to detect cases where manual corrections may be needed; users can then choose whether or not to make them. The validator was written as a simple HTML+JS page that users clone from git and load from a file: URL.
Here is a simplified version of the validator, omitting all of the UI, error handling, and data parsing logic:
function loadFile() {
var filePath;
var reader;
document.getElementById("validation_output").innerHTML = "";
filePath = document.getElementById("fileinput");
reader = new FileReader();
reader.onload = receivedText;
reader.readAsArrayBuffer(filePath.files[0]);
}
function receivedText(e) {
document.getElementById("validation_output").textContent = "Successfully read from file!";
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div>
<input type="file" id="fileinput">
<input type="button" value="Validate File" onclick="loadFile()">
</div>
<div id="validation_output">
</div>
</body>
</html>
In normal use, a user uses the file input to select a file, then clicks "Validate" to run the validation. If the file fails validation, then the user makes edits to the file out of band, then clicks "Validate" again to see if the changes corrected the problems.
The problem is that while the validator works on the initial validation pass, it fails on the second pass if the file changed. The browser doesn't throw an exception or log an error to the console; it just never makes the onload callback. This only happens if the contents of the file change; if I re-validate an unchanged document, then it works as expected. The only work-around that I've identified is to re-load the page and use the file input to select the file again.
How can I make the validator re-load the input file on the second pass?

There seems to be no way around the limitations of FileReader (like its problems to access a chosen file after it has changed).
Solution:
The majority of current browsers (except Firefox) now supports the new File System Access API.
Here is an example on how to use it with changing files.
Unfortunately you will NOT be able to RUN this snippet within Stackoverflow, because showOpenFilePicker() is not allowed in sandboxed documents.
<!DOCTYPE html>
<html>
<head>
<script>
let fileHandle;
async function selectFile() {
[fileHandle] = await window.showOpenFilePicker();
let filenameDiv = document.getElementById('filenameDiv');
filenameDiv.innerHTML = fileHandle.name;
readFile();
};
async function readFile() {
const file = await fileHandle.getFile();
const contents = await file.text();
let outputDiv = document.getElementById('outputDiv');
outputDiv.innerHTML = contents;
}
</script>
</head>
<body>
<div style="margin: 20px;">
<p><button onclick="selectFile()">Choose template file</button></p>
<p><button onclick="readFile()">Reload</button></p>
<div id="filenameDiv" style="background: #fff;"></div>
</div>
<div id="outputDiv" style="background: #fff; min-height: 100px;"></div>
</body>
</html>

Related

strange filename callback after file selection finish

I have this code which will display the file name after file has been selected:
<input id="file-input" type="file" />
<script>
const fileInput = document.querySelector('#file-input');
fileInput.onchange = function(){
console.log('file name:', this.value)
}
</script>
I prepared two windows shortcut file (produced by Desktop ---> right click ---> new ---> shortcut)
the first shortcut file
the target is https://www.baidu.com/ and the file name is www.baidu.com
after i select this file, the output is C:\fakepath\www.baidu.com.url in callback, which is working as expected
the second shortcut file
target is https://www.google.com/ and the file name is www.google.com
but after select this file, i expect it to output C:\fakepath\www.google.com.url in callback, but it outputs something like C:\fakepath\TQCJEVEM
Why is this happening?
Disclaimer: I'm still not sure about the why, but I can make a guess about what is happening.
When you create a windows shortcut (like you mentioned above) where the target is a Network Resource, it creates a URL file that has a .url extension.
NOTE: Microsoft Windows does not display the ".url" file extension even though it exists in the filename. Therefore, URL files saved using Windows web browsers will appear with only the filename prefix.
A URL file on windows looks something like this:
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,11
[InternetShortcut]
IDList=
URL=https://www.baidu.com/
HotKey=0
When you upload the baidu shortcut, windows simply uploads the file with above content.
HOWEVER
When you upload the google shortcut, windows actually downloads a copy of the www.google.com website landing page, stores it in the local cache somewhere in the ..\AppData\Local\Microsoft\Windows\INetCache\.. folder and then uploads that cache file which could have its filename as a randomly generated string. Every new attempt would generate a new string for filename.
Hope this points you in the right direction.
Edit:
To verify the content of the uploaded file, slightly modify your code using sample code from this answer.
function init() {
document.getElementById('fileInput').addEventListener('change', handleFileSelect, false);
}
function handleFileSelect(event) {
const reader = new FileReader()
reader.onload = handleFileLoad;
reader.readAsText(event.target.files[0])
}
function handleFileLoad(event) {
console.log(event);
document.getElementById('fileContent').textContent = event.target.result;
}
<!DOCTYPE html>
<html>
<head>
<script src="script.js"></script>
</head>
<body onload="init()">
<input id="fileInput" type="file" name="file" />
<pre id="fileContent"></pre>
</body>
</html>

Dynamic change of script source not working

I have two files. An HTML file:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function update_layout()
{
var new_source = document.createElement('script')
new_source.src = 'script_code.js'
new_source.type = 'text/javascript'
document.getElementsByTagName('head')[0].appendChild(new_source)
}
function do_layout()
{
alert(Lay_Table['nam'])
}
</script>
</head>
<body>
<input type="button" value="Update" onclick="update_layout();do_layout();"/>
</body>
</html>
and an JavaScript file named "script_code.js":
Lay_Table = {}
Lay_Table['nam'] = 'US 104 Key'
When I click on the "Update" button I get an error instead of an alert containing the text "US 104 Key".
I have looked at very similar questions on Stack Overflow but cannot find out what is wrong. Have I made a mistake, or is this method no longer allowed due to security reasons? I am using Google Chrome.
The script takes a bit of time to get inserted into the document and run - it doesn't happen immediately, so the Lay_Table is not defined in time when do_layout runs. Consider adding a load listener to the inserted tag (and avoid inline handlers, they have way too many problems to be worth using nowadays, such as a demented scope chain and quote escaping issues):
window.addEventListener('DOMContentLoaded', () => {
document.querySelector('input').addEventListener('click', update_layout);
});
function update_layout()
{
var new_source = document.createElement('script')
new_source.src = 'script_code.js'
new_source.addEventListener('load', do_layout);
document.head.appendChild(new_source)
}

jQuery/ Javascript .get method for reading text files

I just started working on my school assignment with some regular expressions in Javascript. I can't seem to figure out how to actually read data from a text file into variable using jQuery method .get(). When I try my code out nothing happens. It seems like it never enters .get() section. Here is my code:
JS file:
document.getElementById('file').onchange = function(){
var file = "New Text Document.txt"; //this will later be the selected file
$.get(file,function(data){
var myVar = data;
$("#123").html(myVar);
});
};
HTML file:
<!DOCTYPE html>
<html>
<head>
<title>animacija</title>
<meta charset="UTF-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
</head>
<body>
<input type="file" name="file" id="file">
<script type="text/javascript" src="func.js"></script>
<div id="123"></div>
</body>
</html>
The code snippet seems to be ok, but it will not work locally since $.get is for ajax requests and requires full available server path.
I rather recommend you the use of FileReader API.
HTML
<title>animacija</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<body>
<input type="file" name="file" id="file">
<div id="123"></div>
</body>
JavaScript
document.getElementById('file').onchange = function() {
var file = this.files[0];
var FR = new FileReader();
FR.readAsText(file);
FR.onload = function(data) {
var myVar = data.target.result;
$("#123").html(myVar);
}
};
JSFiddle
Hope it works for you!
Most browsers will not allow file: resources to read other local files. This is to prevent attacks where a downloaded HTML document could start reading (and transmitting) the contents of your hard drive (or at least your Downloads folder) as soon as you open it.
The other thing you need to know here is that $.get is used for getting resources from an HTTP server, while file inputs are used to allow a user to select a file from their local drive. I realize in your case it's a little confusing, because your web page is on your local hard drive, but imagine if your HTML and scripts were being hosted online, and some other user (not you) was using them to process their own locally-stored files.
MDN has a good tutorial on how to get started with <input type="file"> inputs.
The code won't work locally due to cross-origin limitations.
It works fine when run on a remote server and all files are in the same folder.
If you want to read local files (aka. files selected by user through the file input) you can read more about FileAPI here:
https://www.html5rocks.com/en/tutorials/file/dndfiles/

passing csv file to Ruby using JS and html's input File API

I'm trying to build basic CSV editor which uses html+css as a UI, and Ruby doing the string parsing and manipulation.
function passFileToRuby (f) {
var reader = new FileReader(),
txt
reader.readAsText(f);
txt = reader.result
return txt
}
and some html:
<html>
<head>
<script src="../js/script.js"></script>
</head>
<body>
<h1>CSVEditor!</h1>
<form action="/form" method="post">
<input type="file" name="file" id="input" onchange="passFileToRuby(this.files[0])">
<input type="submit">
</form>
</body>
</html>
I am trying to load a csv file via html form, pass it to Ruby (Sinatra) which will split it and render it as table content.
When I load a file and then enter the contents of passFileToRuby() line after line everything seems to work - console.log(txt) prints the contents of the file to the screen. When I pass it to onchange attribute as a passFileToRuby function however, it returns nothing, txt is null.
Please advise.
The file might not be loaded yet when the input changes - it's too soon. When you access from the console, the browser has had the time to upload the contents.
Try attaching a loaded event handler to reader instead of accessing its result directly.
var reader = new FileReader();
reader.onload = function(evt) {
handleText(reader.result);
}
reader.readAsText(f);
and implement handleText appropriately.

Javascript to check filesize before upload in Internet Explorer

Is it possible to use Javascript to check for a file's size (at the client side) before it is actually uploaded to the server?
The application is built on EXTJS and Java and is restricted to usage by Internet Explorere 7 on Windows XP machines. No usage of activeX is allowed.
The workflow is as such:
User selects a file to upload.
Validation kicks in immediately to check for file type and filesize.
If filesize exceeds limit, the GUI will prompt with error.
If filesize is within the limit, the full filepath will be passed to the server end (java servlet) to be uploaded.
Is the filesize check and reading of full file path possible to be achieved with javascript?
It is possible with ActiveX Objects.
<html>
<head>
<script>
function getSize()
{
var myFSO = new ActiveXObject("Scripting.FileSystemObject");
var filepath = document.upload.file.value;
var thefile = myFSO.getFile(filepath);
var size = thefile.size;
alert(size + " bytes");
}
</script>
</head>
<body>
<form name="upload">
<input type="file" name="file">
<input type="button" value="Size?" onClick="getSize();">
</form>
</body>
</html>
There's currently no way to portably check the size of an uploaded file from the web browser. The HTML5 File API makes this possible, but that's not available in MSIE7 -- it's currently on track for MSIE10.
There is intentionally no way to determine the full path of an uploaded file, as that may include sensitive information, like the name of the end user.
The reason you can't is because it would be bad if browsers, and javascript, could access the clients filesystem.
This is actively denied and can be seen as an attack.
Using jQuery, Restricting File Size Before Uploading
Please try below code,
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.js"></script>
<script type="text/javascript">
$(function() {
$("document").ready(function(){
$("#myFile1").change(function() {
var f1=document.getElementById("myFile1").value;
if((f.size||f.fileSize)==09765625)
{
alert("file size is less than 1mb");
}
else
{
alert("file size should not exceed more than 1mb");
$(this).val($.data(this, 'f'));
return false;
}
});
});
})
</script>
</head>
<body>
<input type='file' name="file" id="myFile1" />
</body>
</html>

Categories

Resources