FileReader load 事件异步设置 .result 值。要访问.result,请使用load 或loadend 事件。
当在<input type="file">Choose File 或Browse... UI 中选择了文件时,在本地文件系统中删除文件不应影响FileList 处由.files 调用返回的File 对象。见2.9.2. Transferable objects、6.7.3 The DataTransfer interface。
4. The Blob Interface and Binary Data
每个Blob 必须有一个内部快照状态,它
必须初始设置为底层存储的状态(如果有)
这种底层存储存在,并且必须通过
structured clone。 snapshot state的进一步规范定义见Files。
2.9.8 Monkey patch for Blob and FileList objects
这个猴子补丁将在适当的时候被删除。见w3c/FileAPI
issue 32。
Blob 对象是cloneable objects。
每个 Blob 对象的 [[Clone]] 内部方法,给定 targetRealm 并忽略内存,必须运行以下步骤:
如果这是closed,则抛出"DataCloneError" DOMException。
在targetRealm中返回一个新的this实例,对应于
相同的基础数据。
FileList 对象是cloneable objects。
每个FileList对象的[[Clone]]内部方法,给定
targetRealm 和 memory,必须运行这些步骤:
让 output 成为 targetRealm 中的新 FileList 对象。
对于 this 中的每个 file,添加 ? [StructuredClone][15](_file, targetRealm, memory_) 到 File 对象列表的末尾
输出。
返回输出。
在 webkit 和 firefox 浏览器中选择只读文件或文件夹
在 chrome 中,如果为本地文件系统中的文件设置了只读权限,并且用户在 <input type="file"> 元素处选择文件,其中FileReader 用于读取文件,则会在 FileReader 处引发错误,生成自FileReaderprogress 事件。
如果将Blob URL 设置为相同的文件对象,则blob: URL 将不会根据Blob URL 的请求返回只读文件。
选择文件夹权限设置为只读的文件夹
铬、铬
在 chrome 中,设置了 webkitdirectory 属性并选择具有只读权限的文件夹 FileList .length 的 event.target.files 的 chromium 返回了 0; event.target.files.webkitGetAsEntry() 未被调用,"No file chosen" 在 <input type="file"> shadowDOM 处呈现。将文件夹拖放到<input type="file"> 或设置droppable 属性的元素时,只读文件夹的目录.name 和.path 将显示在drop event.dataTransfer。
当用户在<textarea> 元素处放置文件或文件夹时,没有附加drop 事件beforeunload 事件被调用并在UI 上显示提示
Do you want to leave this site?
Changes you made may not be saved.
<Stay><Leave> // <buttons>
火狐
在 Firefox 版本 47.0b9 中,allowdirs 属性设置为 <input type="file"> 元素,其中用户单击 "Choose folder.." <input>,可以通过 .then() 访问父文件夹的文件夹 .name 和 .path链接到event.target.getFilesAndDirectories()。递归迭代Directory条目时,不返回所选文件夹中包含的文件或文件夹;返回一个空字符串。
如果用户点击"Choose file..."<input>并选择了一个没有设置只读权限的文件夹,当点击文件管理器中的文件夹时,会列出该文件夹中的文件。
如果选择了设置了只读权限的文件夹,则会在 UI 显示时呈现alert() 通知
Could not read the contents of <directory name>
Permission denied
错误、安全问题
*nix 操作系统
当用户在<textarea> 元素处放置文件夹时,没有附加drop 事件,用户文件系统file: 协议处的文件夹的完整路径将被暴露。文件夹中包含的文件的路径也没有设置为.value;例如,
"file:///home/user/Documents/Document/"
当文件在<textarea> 元素处被删除时,其中未附加drop 事件,用户文件系统中文件的完整路径设置为.value of <textarea>;也就是说,
"file:///home/user/Documents/Document/MyFileFullPathDisplayedAtTextAreaValue.txt"
如果在<textarea>元素处选择并删除了多个文件,则所有完整文件路径都设置为.value of <textarea>,由换行符\n界定
"file:///home/user/Documents/Document/MyFileFullPathDisplayedAtTextAreaValue1.txt"
"file:///home/user/Documents/Document/MyFileFullPathDisplayedAtTextAreaValue2.txt"
..
为文件路径创建XMLHttpRequest() 并在console 记录错误
NS_ERROR_DOM_BAD_URI: Access to restricted URI denied
当设置为<img> 元素的.src 且.crossOrigin 设置为"anonymous" 时,将调用img error 事件处理程序
调用window.open()并在第一个参数处设置完整路径
Error: Access to '"file:///home/user/Documents/Document/MyFileFullPathDisplayedAtTextAreaValue.png"' from script denied
规格
4.10.5.1.18. File Upload state (type=file)
EXAMPLE 16
由于历史原因,value IDL 属性作为前缀
带有字符串“C:\fakepath\”的文件名。一些旧版用户代理
实际上包括完整路径(这是一个安全漏洞)。
因此,从value IDL 获取文件名
向后兼容的属性是不平凡的。
4.10.5.4. Common <input> element APIs
文件名
在获取时,它必须返回字符串“C:\fakepath\”,后跟selected
files 列表中的第一个文件的名称(如果有),如果列表为空,则返回空字符串。在
设置,如果新值是空字符串,它必须清空列表
selected files;否则,它必须抛出一个“InvalidStateError”
DOMException.
注意:这种“虚假路径”要求是历史的不幸事故。有关更多信息,请参阅File Upload 状态部分中的示例
信息。
注意:由于selected files列表中的文件名中不允许出现path components,因此“\fakepath\”不能误认
用于路径组件。
4.10.5.1.18. File Upload state (type=file)
路径组件
当<input> 元素的type 属性在File Upload 中时
声明,本节中的规则适用。
<input> 元素 represents selected files 的列表,
每个文件由文件名、文件类型和文件主体(
文件的内容)。
文件名不能包含path components,即使是
用户选择了整个目录层次结构或多个文件
来自不同目录的相同名称。 路径组件,用于
File Upload 状态的目的是文件名的那些部分
由 U+005C REVERSE SOLIDUS 字符 () 字符分隔。
错误报告https://bugzilla.mozilla.org/show_bug.cgi?id=1311823
在数据 URI 的
Neal Deakin 在错误报告中的评论
我认为提到的步骤是:
- 打开数据:文本/html,
- 将文件从桌面拖到文本区域
我可以在 Linux 上重现这个,但不能在 Windows 或 Mac 上重现。
上面的预感是正确的; Linux 将数据包含为 url 和
明文也是如此。
在 data: prototcol data URI 在 firefox 和 chrome、chromium 中删除文件
data:text/html,<textarea></textarea>
火狐
文件或文件夹的完整路径名设置为.value of <textarea>。
铬、铬
在data URI 放置文件在chrome 中只有textarea 元素,chromium 用地址栏上放置的文件路径替换data URI,并在同一选项卡中加载放置的文件,用内容替换data URI删除的文件。
plnkrhttp://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 事件来处理用户的文件选择操作。
用<textarea> 元素替换<p> 元素以显示来自.readAsText() 调用的load 事件的结果。
要在click 在button 元素处显示FileReader 中的.result,请将load 内load 的FileReader 事件设置为reader.result 内的变量text 设置为click@6。 .textContent 的 #DisplayText 元素到变量引用之前设置的 reader.result。
<!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>