简体   繁体   English

HTML5 File API 中的 FileReader.readAsText 如何工作?

[英]How FileReader.readAsText in HTML5 File API works?

I wrote the following code to check whether the uploaded file exists or not using HTML5 file API.我编写了以下代码来使用 HTML5 文件 API 检查上传的文件是否存在。

 <input type="file" id="myfile"> <button type="button" onclick="addDoc()">Add Document</button> <p id="DisplayText"></p>

The following JavaScript code has been mapped to it is as follows:以下 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>*/
}

After browsing a file from local system I tried to delete the "browsed" document form the folder before clicking on addDoc() .从本地系统浏览文件后,我尝试在单击addDoc()之前从文件夹中删除“浏览过的”文档。 After clicking the button I could still see Filereader.result is not null and could display all the content.单击按钮后,我仍然可以看到Filereader.result不为空,并且可以显示所有内容。

Can someone explain on how the Filereader works?有人可以解释Filereader 的工作原理吗? Is it that the FileReader gets bound as soon as the file is browsed? FileReader是否在浏览文件后立即绑定?

Also can we check whether the system Readonly Attribute with FileReader similar to Java File.canread() ?也可以用类似于Java File.canread() FileReader来检查系统的Readonly属性吗?

Could someone suggest on this?有人可以对此提出建议吗? I have IE11 to test the code.我有 IE11 来测试代码。

FileReader load event sets the .result value asynchronously. FileReader load事件异步设置.result值。 To access the .result use load or loadend event.要访问.result使用loadloadend事件。

When a file has been selected at <input type="file"> Choose File or Browse... UI, deleting file at local filesystem should not effect the File object at FileList returned by .files call.当在<input type="file"> Choose FileBrowse... UI 中Choose File ,在本地文件系统中删除文件不应影响.files调用返回的FileListFile对象。 See 2.9.2.2.9.2。 Transferable objects , 6.7.3 The DataTransfer interface . 可传输对象6.7.3 DataTransfer 接口

4. The Blob Interface and Binary Data 4. Blob 接口和二进制数据

Each Blob must have an internal snapshot state , which must be initially set to the state of the underlying storage, if any such underlying storage exists, and must be preserved through structured clone .每个Blob必须有一个内部快照 state ,它必须最初设置为底层存储的状态(如果存在任何此类底层存储),并且必须通过structured clone保存。 Further normative definition of snapshot state can be found for File s.可以为File找到snapshot state进一步规范定义。

2.9.8 Monkey patch for Blob and FileList objects 2.9.8 Blob 和 FileList 对象的 Monkey 补丁

This monkey patch will be removed in due course.这个猴子补丁将在适当的时候删除。 See w3c/FileAPI issue 32 .请参阅w3c/FileAPI 问题 32

Blob objects are cloneable objects . Blob对象是可cloneable objects

  1. Each Blob object's [[ Clone ]] internal method, given targetRealm and ignoring memory, must run these steps:每个Blob对象的 [[ Clone ]] 内部方法,给定 targetRealm 并忽略内存,必须运行以下步骤:

  2. If this is closed , then throw a "DataCloneError" DOMException .如果这是closed ,则抛出一个"DataCloneError" DOMException

Return a new instance of this in targetRealm , corresponding to the same underlying data.targetRealm 中返回this 的一个新实例,对应于相同的底层数据。

FileList objects are cloneable objects . FileList对象是可克隆的对象

Each FileList object's [[Clone]] internal method, given targetRealm and memory , must run these steps:每个FileList对象的[[Clone]]内部方法,给定targetRealmmemory ,必须运行以下步骤:

  1. Let output be a new FileList object in targetRealm .output成为targetRealm 中的一个新FileList对象。

  2. For each file in this , add ?对于图中的每个文件,添加? [StructuredClone][15](_file, targetRealm, memory_) to the end of the list of File objects of output . [StructuredClone][15](_file, targetRealm, memory_)输出File对象列表的末尾。

Return output .返回输出


Selecting read-only files or folders at webkit and firefox browsers在 webkit 和 firefox 浏览器中选择只读文件或文件夹

At chrome, chromium if read-only permission is set for file at local filesystem and user selects file at <input type="file"> element, where FileReader is used to read file, an error is thrown at FileReader , generated from FileReader progress event.在 chrome 中,如果在本地文件系统中为文件设置了只读权限,并且用户在<input type="file">元素处选择文件,其中FileReader用于读取文件,则会在FileReader处引发错误,由FileReader progress生成事件。

If a Blob URL is set to the same file object, the blob: URL will not return the the read-only file at request to the Blob URL .如果Blob URL设置为相同的文件对象,则blob: URL 不会在请求时将只读文件返回给Blob URL

Selection of folder where folder permission is set to read-only选择文件夹权限设置为只读的文件夹

Chrome, chromium铬、铬

At chrome, chromium where webkitdirectory attribute is set and folder is selected with read-only permission FileList .length of event.target.files returned 0 ;在 chrome 中,设置了webkitdirectory属性并选择具有只读权限的文件夹FileList .length of event.target.files返回0 event.target.files.webkitGetAsEntry() is not called, "No file chosen" is rendered at <input type="file"> shadowDOM . event.target.files.webkitGetAsEntry()未被调用,在<input type="file"> shadowDOM处呈现"No file chosen""No file chosen" <input type="file"> When a folder is dropped at <input type="file"> or element where droppable attribute set, the directory .name and .path of the read-only folder is displayed at drop event.dataTransfer .当文件夹放置在<input type="file">或放置droppable属性的元素处时,只读文件夹的目录.name.path显示在drop event.dataTransfer

When user drops file or folder at <textarea> element, where no drop event is attached beforeunload event is called and a prompr is displayed at UI当用户删除文件或文件夹在<textarea>元素,在没有drop附着事件beforeunload事件被称为和prompr在UI显示

Do you want to leave this site? Changes you made may not be saved. <Stay><Leave> // <buttons>

Firefox火狐

At firefox version 47.0b9 with allowdirs attribute is set at <input type="file"> element, where user clicks "Choose folder.." <input> , the folder .name and .path of the parent folder are accessible at .then() chained to event.target.getFilesAndDirectories() .在火狐版本47.0b9与allowdirs属性被设置在<input type="file">元素,其中用户点击"Choose folder.." <input> ,该文件夹.name.path的父文件夹是在可访问的.then()链接到event.target.getFilesAndDirectories() The files or folders contained within the selected folder are not returned when recursively iterating Directory entries;递归迭代Directory条目时,不会返回所选文件夹中包含的文件或文件夹; an an empty string is returned.返回一个空字符串。

If user clicks "Choose file..." <input> and a folder is selected without read-only permission set, when the folder at file manager is clicked, the files in the folder are listed.如果用户单击"Choose file..." <input>并且选择了一个没有设置只读权限的文件夹,则单击文件管理器中的文件夹时,将列出该文件夹中的文件。

Where a folder is selected where read-only permission is set an alert() notification is rendered at UI displaying如果选择了设置只读权限的文件夹,则会在 UI 显示时呈现alert()通知

 Could not read the contents of <directory name> Permission denied

Bug, security issue错误,安全问题

*nix OS *nix 操作系统

When user drops folder at <textarea> element, where no drop event is attached, the full path to the folder at user filesystem file: protocol is exposed.当用户在<textarea>元素放置文件夹时,没有drop事件附加,用户文件系统file:协议中file:夹的完整路径被公开。 The paths to the files contained within the folder are not also set as .value ;文件夹中包含的文件的路径也没有设置为.value eg,例如,

 "file:///home/user/Documents/Document/"

When a file is dropped at <textarea> element, where not drop event is attached, the full path to the file at user filesystem is set as .value of <textarea> ;当一个文件在丢弃<textarea>元素,其中不drop被附加事件,在用户文件系统中的文件的完整路径被设定为.value<textarea> ; that is,也就是说,

 "file:///home/user/Documents/Document/MyFileFullPathDisplayedAtTextAreaValue.txt"

If multiple files are selected and dropped at <textarea> element, all of the full file paths are set as .value of <textarea> , delineated by new line character \\n如果在<textarea>元素中选择并放置多个文件,则所有完整文件路径都设置为<textarea> .value ,以换行符分隔\\n

 "file:///home/user/Documents/Document/MyFileFullPathDisplayedAtTextAreaValue1.txt" "file:///home/user/Documents/Document/MyFileFullPathDisplayedAtTextAreaValue2.txt" ..

Where an XMLHttpRequest() is made for the file path and error is logged at console为文件路径创建XMLHttpRequest()并在console记录错误的地方

NS_ERROR_DOM_BAD_URI: Access to restricted URI denied

When set as .src of an <img> element with .crossOrigin set to "anonymous" the img error event handler is called如果被设置为.src一个的<img>与元件.crossOrigin设置为"anonymous"img error事件处理程序被调用

At call to window.open() with full path set at first parameter在调用window.open() ,在第一个参数中设置了完整路径

Error: Access to '"file:///home/user/Documents/Document/MyFileFullPathDisplayedAtTextAreaValue.png"' from script denied

Specification规格

4.10.5.1.18. 4.10.5.1.18。 File Upload state ( type=file ) 文件上传状态( type=file

EXAMPLE 16 例 16

For historical reasons, the value IDL attribute prefixes the file name with the string " C:\\fakepath\\ ".由于历史原因, value IDL 属性在文件名前加上字符串“ C:\\fakepath\\ ”。 Some legacy user agents actually included the full path (which was a security vulnerability).一些旧的用户代理实际上包含了完整路径(这是一个安全漏洞)。 As a result of this, obtaining the file name from the value IDL attribute in a backwards-compatible way is non-trivial.因此,以向后兼容的方式从value IDL 属性中获取文件名并非易事。

4.10.5.4. 4.10.5.4. Common <input> element APIs 常见的<input>元素 API

filename文件名

On getting, it must return the string "C:\\fakepath\\" followed by the name of the first file in the list of selected files , if any, or the empty string if the list is empty.获取时,它必须返回字符串 "C:\\fakepath\\" 后跟selected files列表中第一个文件的名称(如果有),或者如果列表为空,则返回空字符串。 On setting, if the new value is the empty string, it must empty the list of selected files ;设置时,如果新值是空字符串,则必须清空selected files列表; otherwise, it must throw an " InvalidStateError " DOMException .否则,它必须抛出“ InvalidStateErrorDOMException

NOTE: This "fakepath" requirement is a sad accident of history.注意:这个“fakepath”要求是历史上的一个可悲的意外。 See the example in the File Upload state section for more information.有关更多信息,请参阅文件上传状态部分中的示例。

NOTE: Since path components are not permitted in file names in the list of selected files , the " \\fakepath\\ " cannot be mistaken for a path component.注意:由于selected files列表中的文件名中不允许使用path components因此不能将“ \\fakepath\\ ”误认为是路径组件。

4.10.5.1.18. 4.10.5.1.18。 File Upload state ( type=file ) 文件上传状态( type=file

Path components路径组件

When an <input> element's type attribute is in the File Upload state, the rules in this section apply.<input>元素的type属性处于File Upload状态时,本节中的规则适用。

The <input> element represents a list of selected files , each file consisting of a file name, a file type, and a file body (the contents of the file). <input>元素represents selected files的列表,每个文件由文件名、文件类型和文件正文(文件内容)组成。

File names must not containpath components , even in the case that a user has selected an entire directory hierarchy or multiple files with the same name from different directories.文件名不得包含path components ,即使在用户选择了整个目录层次结构或来自不同目录的多个同名文件的情况下。 Path components , for the purposes of the File Upload state, are those parts of file names that are separated by U+005C REVERSE SOLIDUS character () characters.出于File Upload状态的目的,路径组件是文件名中由 U+005C REVERSE SOLIDUS 字符 () 字符分隔的那些部分。

Bug report https://bugzilla.mozilla.org/show_bug.cgi?id=1311823错误报告https://bugzilla.mozilla.org/show_bug.cgi?id=1311823


Dropping file at <textarea> at data URI在数据 URI 的 <textarea> 处删除文件

Following comment by Neal Deakin at bug report遵循Neal Deakin在错误报告中的评论

I think the steps referred to are:我认为提到的步骤是:

  1. Open data:text/html,打开数据:文本/html,
  2. Drag a file from the desktop to the textarea从桌面拖一个文件到textarea

I can reproduce this on Linux, but not on Windows or Mac.我可以在 Linux 上重现这个,但不能在 Windows 或 Mac 上重现。

The hunch above is correct;上面的预感是正确的; Linux is including the data as a url and plaintext as well. Linux 也将数据作为 url 和纯文本包含在内。

dropped files at data: prototcol data URI at firefox, and chrome, chromiumdata:删除文件data: firefox 和 chrome、chrome 上的协议data URI

 data:text/html,<textarea></textarea>

Firefox火狐

The full path name of file or folder set as .value of <textarea> .设置为<textarea> .value的文件或文件夹的完整路径名。

Chrome, chromium铬、铬

Dropping file at data URI having only textarea element at chrome, chromium replaces the data URI with dropped file path at address bar, and loads the dropped file at the same tab, replacing the data URI with the content of the dropped file.在 chrome 上只有textarea元素的data URI处删除文件,chrome 在地址栏用删除的文件路径替换data URI ,并在同一选项卡上加载删除的文件,用删除的文件的内容替换data URI

plnkr http://plnkr.co/edit/ZfAGEAiyLLq8rGXD2ShE?p=preview plnkr http://plnkr.co/edit/ZfAGEAiyLLq8rGXD2ShE?p=preview


html , javascript to reproduce issue described above 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 plnkr http://plnkr.co/edit/8Ovw3IlYKI8BYsLhzV88?p=preview


You can use change event attached to #myfile element to handle file selection action by user.您可以使用附加到#myfile元素的change事件来处理用户的文件选择操作。

Substitute <textarea> element for <p> element to display result of load event from .readAsText() call.<textarea>元素替换为<p>元素以显示来自.readAsText()调用的load事件的结果。

To display .result of FileReader at click at button element, set variable text to reader.result within load event of FileReader at click event at button set .textContent of #DisplayText element to variable referencing previously set reader.result .要显示.resultFileReaderclickbutton元件,组可变textreader.resultload的事件FileReaderclick事件在button.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>

The FileReader object lets web applications asynchronously read the contents of files (or raw data buffers) stored on the user's computer, using File or Blob objects to specify the file or data to read. FileReader 对象允许 Web 应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。

File objects may be obtained from a FileList object returned as a result of a user selecting files using the element, from a drag and drop operation's DataTransfer object, or from the mozGetAsFile() API on an HTMLCanvasElement.文件对象可以从作为用户使用该元素选择文件的结果返回的 FileList 对象、从拖放操作的 DataTransfer 对象或从 HTMLCanvasElement 上的 mozGetAsFile() API 获得。

The readAsText method is used to read the contents of the specified Blob or File. readAsText方法用于读取指定 Blob 或 File 的内容。 When the read operation is complete, the readyState is changed to DONE, the loadend is triggered, and the result attribute contains the contents of the file as a text string.当读操作完成时,readyState 变为 DONE,loadend 被触发,result 属性包含文件内容作为文本字符串。

Syntax语法

instanceOfFileReader.readAsText(blob[, encoding]);

Parameters参数

Blob斑点

The Blob or File from which to read.要从中读取的 Blob 或文件。

encoding Optional编码可选

A string specifying the encoding to use for the returned data.一个字符串,指定用于返回数据的编码。 By default, UTF-8 is assumed if this parameter is not specified.默认情况下,如果未指定此参数,则假定为 UTF-8。

For the metadata about a file we can check the File object F such that: F has a readability state of OPENED.对于有关文件的元数据,我们可以检查 File 对象F ,以便: F 的可读性状态为 OPENED。 F refers to the bytes byte sequence. F 指的是 bytes 字节序列。 F.size is set to the number of total bytes in bytes. F.size设置为以字节为单位的总字节数。 F.name is set to n. F.name设置为 n。 F.type is set to t. F.type设置为 t。

Note: The type t of a File is considered a parsable MIME type if the ASCII-encoded string representing the File object's type, when converted to a byte sequence, does not return undefined for the parse MIME type algorithm [MIMESNIFF].注意:如果表示 File 对象类型的 ASCII 编码字符串在转换为字节序列时不会为解析 MIME 类型算法 [MIMESNIFF] 返回 undefined,则文件的类型 t 被视为可解析 MIME 类型。

F.lastModified is set to d. F.lastModified设置为 d。

See more about browser compatibility and detailed document for FileReader , File and readAsText at MDN, also this W3C draft for FileApi在 MDN 上查看更多关于浏览器兼容性和FileReaderFilereadAsText 的详细文档,以及FileApi 的这个W3C 草案

Use this instead:-改用这个:-

 function loadFileAsText() { var fileToLoad = document.getElementById("fileToLoad").files[0]; var fileReader = new FileReader(); fileReader.onload = function(fileLoadedEvent) { var textFromFileLoaded = fileLoadedEvent.target.result; document.getElementById("inputTextToSave").innerText = textFromFileLoaded; }; fileReader.readAsText(fileToLoad, "UTF-8"); }
 <p>Select a File to Load:</p> <input type="file" id="fileToLoad"><button onclick="loadFileAsText()">Load Selected File</button> <br> <br> <br> <p>Text file loaded:</p> <p id="inputTextToSave"></p>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 来自“ HTML5 File API中的FIleReader.readAsText如何工作”的FileReader错误 - FileReader Error from “How FIleReader.readAsText in HTML5 File API works” HTML5 文件 API:FileReader.readAsText() 返回“未定义” - HTML5 File API: FileReader.readAsText() returns "undefined" 如何在 JavaScript 中同步使用 FileReader.readAsText 读取文件? - How to read file using FileReader.readAsText synchronously in JavaScript? 将FileReader.readAsText()结果字符串转换回文件对象以供下载? - Convert FileReader.readAsText() result string back into a file object for download? 使用 FileReader.readAsText() 将 a.txt 文件拆分为 JavaScript 数组 - Splitting a .txt file into a JavaScript Array using FileReader.readAsText() HTML5 文件 API:如何查看 readAsText() 的结果 - HTML5 File API: How to see the result of readAsText() fileReader.readAsText()JavaScript:未显示结果 - fileReader.readAsText() javascript: result not displayed fileReader.readAsText 返回一个带引号的字符串 - fileReader.readAsText returns a string with quote 抛出&#39;FileReader&#39;的fileReader.readAsText():参数1不是&#39;Blob&#39;类型 - fileReader.readAsText() throwing 'FileReader': parameter 1 is not of type 'Blob' Cordova 文件插件 FileReader.readAsText 获取错误但不调用错误回调 - Cordova File plugin FileReader.readAsText gets error but does not call error callback
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM