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
进一步规范定义可以在File
find。
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()
,并在console
logging错误
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
的列表; 否则,它必须抛出一个“InvalidStateError
”DOMException
。注:这个“假道”的要求是一个悲伤的历史事故。 有关更多信息,请参阅文件上载状态部分中的示例。
注:由于
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报告发表评论之后
我认为提到的步骤是:
- 打开数据: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.result
variables。
<!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草案