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使用loadloadend事件。

当在<input type="file"> Choose FileBrowse... 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

  1. 每个Blob对象的[[ Clone ]]内部方法(targetRealm和忽略内存)都必须执行以下步骤:

  2. 如果这是closed ,则抛出一个"DataCloneError" DOMException

targetRealm中返回一个新的实例,对应于相同的底层数据。

FileList对象是可复制的对象 。

每个FileList对象的[[Clone]]内部方法( targetRealmmemory )都必须执行以下步骤:

  1. 输出成为targetRealm中新的FileList对象。

  2. 对于这个每个文件 ,添加? [StructuredClone][15](_file, targetRealm, memory_)输出File对象列表的末尾。

返回输出


在webkit和Firefox浏览器上select只读文件或文件夹

在chrome中,如果在本地文件系统中为只读文件设置了只读权限,并且用户在<input type="file">元素中select了文件, FileReader用于读取文件, FileReaderFileReader progress生成错误事件。

如果将Blob URL设置为同一个文件对象,则blob: URL将不会返回请求Blob URL的只读文件。

select文件夹权限设置为只读的文件夹

铬,铬

在chrome中,设置了webkitdirectory属性的铬以及select了具有只读权限的文件夹FileListevent.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

由于历史原因, value IDL属性为文件名前加string“ C:\fakepath\ ”。 一些传统用户代理实际上包含完整path(这是一个安全漏洞)。 因此,以向后兼容的方式从value IDL属性获取文件名是非平凡的。

4.10.5.4。 Common <input>元素的API

文件名

获取时,必须返回string“C:\ fakepath \”,后跟selected files列表中的第一个文件的名称(如果有的话),如果列表为空,则返回空string。 在设置时,如果新值是空string,则必须清空selected files的列表; 否则,它必须抛出一个“ InvalidStateErrorDOMException

注:这个“假道”的要求是一个悲伤的历史事故。 有关更多信息,请参阅文件上载状态部分中的示例。

注:由于selected files列表中的文件名中不允许path components因此不能将“ \fakepath\ ”误认为path组件。

4.10.5.1.18。 file upload状态( type=file

path组件

<input>元素的type属性处于“ File Upload状态时,将应用本节中的规则。

<input>元素represents selected 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报告发表评论之后

我认为提到的步骤是:

  1. 打开数据:text / html,
  2. 将文件从桌面拖到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


htmljavascript重现上述问题

 <!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.resultFileReader load事件中将variablestext设置为reader.resultclickbutton事件处设置.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草案