HTML5 File API中的FileReader.readAsText如何工作?
我写了下面的代码来检查上传的文件是否存在或不使用HTML5文件API。
<input type="file" id="myfile"> <button type="button" onclick="addDoc()">Add Document</button> <p id="DisplayText"></p>
以下JavaScript代码已被映射到它如下:
function addDoc() { var file=document.getElementById("myFile").files[0]; //for input type=file var reader=new FileReader(); reader.onload = function(e) {} reader.readAsText(file); var error = reader.error; var texte=reader.result; document.getElementById("DisplayText").innerText=reader.result; /*<p id="DisplayText>*/ }
在从本地系统浏览文件之后,我尝试在点击addDoc()之前删除文件夹中的“浏览”文档。 点击button后,我仍然可以看到Filereader.result不是空的,可以显示所有的内容。
有人可以解释如何Filereader的作品? 文件被浏览后, FileReader是否被绑定?
我们也可以检查系统Readonly属性是否与FileReader类似,Java File.canread() ?
有人可以build议吗? 我有IE11来testing代码。
FileReader load事件asynchronous设置.result值。 要访问loadend使用load或loadend事件。
当在<input type="file"> Choose File或Browse... UI,在本地文件系统中删除文件不应影响File系统返回的File对象。 见2.9.2。 可转移对象 , 6.7.3 DataTransfer接口 。
4. Blob接口和二进制数据
每个
Blob必须具有内部快照状态 ,如果存在任何此类基础存储,则必须将其初始设置为基础存储的状态,并且必须通过structured clone保留。snapshot state进一步规范定义可以在Filefind。
2.9.8 Blob和FileList对象的Monkey修补程序
这个猴子补丁将在适当的时候被删除。 请参阅w3c / FileAPI问题32 。
Blob对象是可cloneable objects。
每个
Blob对象的[[Clone]]内部方法(targetRealm和忽略内存)都必须执行以下步骤:如果这是
closed,则抛出一个"DataCloneError"DOMException。在targetRealm中返回一个新的实例,对应于相同的底层数据。
FileList对象是可复制的对象 。每个
FileList对象的[[Clone]]内部方法( targetRealm和memory )都必须执行以下步骤:
让输出成为targetRealm中新的
FileList对象。对于这个每个文件 ,添加?
[StructuredClone][15](_file, targetRealm, memory_)到输出的File对象列表的末尾。返回输出 。
在webkit和Firefox浏览器上select只读文件或文件夹
在chrome中,如果在本地文件系统中为只读文件设置了只读权限,并且用户在<input type="file">元素中select了文件, FileReader用于读取文件, FileReader从FileReader progress生成错误事件。
如果将Blob URL设置为同一个文件对象,则blob: URL将不会返回请求Blob URL的只读文件。
select文件夹权限设置为只读的文件夹
铬,铬
在chrome中,设置了webkitdirectory属性的铬以及select了具有只读权限的文件夹FileList的event.target.files返回0 ; 没有调用event.target.files.webkitGetAsEntry() ,在<input type="file"> shadowDOM呈现"No file chosen" shadowDOM 。 将文件夹放在<input type="file">或设置了droppable属性的元素上时,只读文件夹的目录.name和.path将显示在drop event.dataTransfer 。
当用户在<textarea>元素处放置文件或文件夹时,在调用beforeunload事件之前没有附加任何drop事件,并在UI中显示一个prompr
Do you want to leave this site? Changes you made may not be saved. <Stay><Leave> // <buttons>
火狐
在带有allowdirs属性的firefox版本47.0b9被设置在<input type="file">元素,其中用户点击"Choose folder.." <input> ,父文件夹的文件夹.name和.path可以在.then()链接到event.target.getFilesAndDirectories() 。 recursion迭代Directory条目时,不会返回选定文件夹中包含的文件或文件夹; 一个空string被返回。
如果用户单击"Choose file..." <input>并且select了没有只读权限集的文件夹,则单击文件pipe理器中的文件夹时,将列出文件夹中的文件。
在设置了只读权限的情况下select文件夹的情况下,会在UI显示时呈现alert()通知
Could not read the contents of <directory name> Permission denied
错误,安全问题
* nix操作系统
当用户将文件夹放在<textarea>元素处,其中没有drop事件时,将显示用户文件系统file:协议file:夹的完整path。 包含在文件夹中的文件的path也不会被设置为.value ; 例如,
"file:///home/user/Documents/Document/"
当一个文件在<textarea>元素处被删除时,在不附加drop事件的情况下,用户文件系统的文件的完整path被设置为<textarea> 。 那是,
"file:///home/user/Documents/Document/MyFileFullPathDisplayedAtTextAreaValue.txt"
如果在<textarea>元素中select了多个文件并将其拖放,则所有完整的文件path将被设置为<textarea> .value ,由换行符描述\n
"file:///home/user/Documents/Document/MyFileFullPathDisplayedAtTextAreaValue1.txt" "file:///home/user/Documents/Document/MyFileFullPathDisplayedAtTextAreaValue2.txt" ..
在哪里为文件path创buildXMLHttpRequest() ,并在consolelogging错误
NS_ERROR_DOM_BAD_URI: Access to restricted URI denied
当将.crossOrigin设置为"anonymous" ,将<img>元素的.crossOrigin设置为img error事件处理程序
在第一个参数设置完整path的情况下调用window.open()
Error: Access to '"file:///home/user/Documents/Document/MyFileFullPathDisplayedAtTextAreaValue.png"' from script denied
规范
4.10.5.1.18。 file upload状态( type=file )
例子16
由于历史原因,
valueIDL属性为文件名前加string“C:\fakepath\”。 一些传统用户代理实际上包含完整path(这是一个安全漏洞)。 因此,以向后兼容的方式从valueIDL属性获取文件名是非平凡的。
4.10.5.4。 Common <input>元素的API
文件名
获取时,必须返回string“C:\ fakepath \”,后跟
selected files列表中的第一个文件的名称(如果有的话),如果列表为空,则返回空string。 在设置时,如果新值是空string,则必须清空selected files的列表; 否则,它必须抛出一个“InvalidStateError”DOMException。注:这个“假道”的要求是一个悲伤的历史事故。 有关更多信息,请参阅文件上载状态部分中的示例。
注:由于
selected files列表中的文件名中不允许path components因此不能将“\fakepath\”误认为path组件。
4.10.5.1.18。 file upload状态( type=file )
path组件
当
<input>元素的type属性处于“File Upload状态时,将应用本节中的规则。
<input>元素representsselected files的列表,每个文件由文件名,文件types和文件体(文件内容)组成。即使用户从不同的目录中select了一个完整的目录层次结构或多个具有相同名称的文件,文件名也不能包含
path components。 用于File Upload状态的path组件是由U + 005C REVERSE SOLIDUS字符()字符分隔的文件名的那些部分。
错误报告https://bugzilla.mozilla.org/show_bug.cgi?id=1311823
在数据URI处放置<textarea>处的文件
在Neal Deakin对bug报告发表评论之后
我认为提到的步骤是:
- 打开数据:text / html,
- 将文件从桌面拖到textarea
我可以在Linux上重现这一点,但不能在Windows或Mac上重现。
上面的预感是正确的。 Linux将数据包含为URL和明文。
data:丢失的文件data: firefox的prototcol data URI ,以及铬,铬
data:text/html,<textarea></textarea>
火狐
文件或文件夹的完整path名称设置为<textarea> .value 。
铬,铬
在chrome中只有textarea元素的data URI删除文件,铬在地址栏中用删除的文件pathreplacedata URI ,并在相同的选项卡上加载删除的文件,用被删除文件的内容replacedata URI 。
plnkr http://plnkr.co/edit/ZfAGEAiyLLq8rGXD2ShE?p=preview
html , javascript重现上述问题
<!DOCTYPE html> <html> <head> <style> body { height: 400px; } textarea { width: 95%; height: inherit; } </style> <script> window.onload = function() { var button = document.querySelector("#myfile + button"); var input = document.getElementById("myfile"); var display = document.getElementById("DisplayText"); var text = null; function readFullPathToFileOnUserFileSystem(e) { var path = e.target.value; console.log(path); var w = window.open(path, "_blank"); var img = new Image; img.crossOrigin = "anonymous"; img.onload = function() { document.body.appendChild(this); } img.onerror = function(err) { console.log("img error", err.message) } img.src = path; var request = new XMLHttpRequest(); request.open("GET", path.trim(), true); request.onload = function() { console.log(this.responseText) } request.error = function(err) { console.log(err.message) } request.send(); } display.addEventListener("input", readFullPathToFileOnUserFileSystem); input.addEventListener("change", addDoc); input.addEventListener("progress", function(event) { console.log("progress", event) }); button.addEventListener("click", handleText) function addDoc(event) { var mozResult = []; function mozReadDirectories(entries, path) { console.log("dir", entries, path); return [].reduce.call(entries, function(promise, entry) { return promise.then(function() { console.log("entry", entry); return Promise.resolve(entry.getFilesAndDirectories() || entry) .then(function(dir) { console.log("dir getFilesAndDirectories", dir) return dir }) }) }, Promise.resolve()) .catch(function(err) { console.log(err, err.message) }) .then(function(items) { console.log("items", items); var dir = items.filter(function(folder) { return folder instanceof Directory }); var files = items.filter(function(file) { return file instanceof File }); if (files.length) { console.log("files:", files, path); mozResult = mozResult.concat.apply(mozResult, files); } if (dir.length) { console.log(dir, dir[0] instanceof Directory, dir[0]); return mozReadDirectories(dir, dir[0].path || path); } else { if (!dir.length) { return Promise.resolve(mozResult).then(function(complete) { return complete }) } } }) .catch(function(err) { console.log(err) }) }; console.log("files", event.target.files); if ("getFilesAndDirectories" in event.target) { return (event.type === "drop" ? event.dataTransfer : event.target) .getFilesAndDirectories() .then(function(dir) { if (dir[0] instanceof Directory) { console.log(dir) return mozReadDirectories(dir, dir[0].path || path) .then(function(complete) { console.log("complete:", complete); event.target.value = null; }); } else { if (dir[0] instanceof File && dir[0].size > 0) { return Promise.resolve(dir) .then(function(complete) { console.log("complete:", complete); }) } else { if (dir[0].size == 0) { throw new Error("could not process '" + dir[0].name + "' directory" + " at drop event at firefox, upload folders at 'Choose folder...' input"); } } } }).catch(function(err) { console.log(err) }) } var reader = new FileReader(); reader.onload = function(e) { text = reader.result; console.log("FileReader.result", text); button.removeAttribute("disabled"); } reader.onerror = function(err) { console.log(err, err.loaded, err.loaded === 0, file); button.removeAttribute("disabled"); } reader.onprogress = function(e) { console.log(e, e.lengthComputable, e.loaded, e.total); } reader.readAsArrayBuffer(file); } function handleText() { // do stuff with `text`: `reader.result` from `addDoc` display.textContent = text; button.setAttribute("disabled", "disabled"); // set `text` to `null` if not needed or referenced again text = null; } } </script> </head> <body> <input type="file" id="myfile" webkitdirectory directory allowdirs> <button type="button" disabled>Add Document</button> <br> <br> <textarea id="DisplayText"></textarea> </body> </html>
plnkr http://plnkr.co/edit/8Ovw3IlYKI8BYsLhzV88?p=preview
您可以使用附加到#myfile元素的change事件来处理用户的文件select操作。
将<textarea>元素replace为<p>元素以显示来自.readAsText()调用的load事件的结果。
click button元素,显示FileReader reader.result在FileReader load事件中将variablestext设置为reader.result , click在button事件处设置.textContent of #DisplayText元素到引用先前设置的reader.resultvariables。
<!DOCTYPE html> <html> <style> body { height: 400px; } textarea { width:95%; height: inherit; } </style> <head> <script> window.onload = function() { var button = document.querySelector("#myfile + button"); var input = document.getElementById("myfile"); var display = document.getElementById("DisplayText"); var text = null; input.addEventListener("change", addDoc); button.addEventListener("click", handleText) function addDoc(event) { var file = this.files[0] var reader = new FileReader(); reader.onload = function(e) { text = reader.result; button.removeAttribute("disabled"); } reader.onerror = function(err) { console.log(err, err.loaded , err.loaded === 0 , file); button.removeAttribute("disabled"); } reader.readAsText(event.target.files[0]); } function handleText() { // do stuff with `text`: `reader.result` from `addDoc` display.textContent = text; button.setAttribute("disabled", "disabled"); // set `text` to `null` if not needed or referenced again text = null; } } </script> </head> <body> <input type="file" id="myfile" accept="text/*"> <button type="button" disabled>Add Document</button><br><br> <textarea id="DisplayText"></textarea> </body> </html>
FileReader对象允许Web应用程序使用File或Blob对象asynchronous读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,以指定要读取的文件或数据。
文件对象可以从作为用户使用元素select文件,从拖放操作的DataTransfer对象或从HTMLCanvasElement上的mozGetAsFile()APIselect文件返回的FileList对象中获得。
readAsText方法用于读取指定的Blob或File的内容。 当读取操作完成时,readyState被改变为DONE,加载被触发,并且结果属性以文本string的forms包含文件的内容。
句法
instanceOfFileReader.readAsText(blob[, encoding]);
参数
斑点
Blob或文件从中读取。
编码可选
指定用于返回数据的编码的string。 默认情况下,如果未指定此参数,则假定为UTF-8。
对于关于文件的元数据,我们可以检查File对象F ,使得:F具有OPENED的可读性状态。 F是指字节字节序列。 F.size被设置为以字节为单位的总字节数。 F.name设置为n。 F.type设置为t。
注意:如果表示File对象types的ASCII编码的string转换为字节序列时,文件的typest被认为是可分析的MIMEtypes,对于分析MIMEtypesalgorithm[MIMESNIFF],则不返回undefined。
F.lastModified设置为d。
有关浏览器兼容性的详细信息以及MDN上的FileReader , File和readAsText的详细文档,以及此FileApi的W3C草案