javascript html5 drag-and-drop textarea fileapi

javascript - ¿Cómo funciona FileReader.readAsText en HTML5 File API?



drag-and-drop textarea (2)

Escribí el siguiente código para verificar si el archivo cargado existe o no usando la API de archivo HTML5.

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

El siguiente código JavaScript que se ha asignado es el siguiente:

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>*/ }

Después de examinar un archivo del sistema local, intenté eliminar el documento "examinado" de la carpeta antes de hacer clic en addDoc() . Después de hacer clic en el botón, todavía podía ver Filereader.result no es nulo y podría mostrar todo el contenido.

¿Alguien puede explicar cómo funciona Filereader ? ¿Es que FileReader queda vinculado tan pronto como se navega por el archivo?

¿También podemos verificar si el sistema de atributo de solo lectura con FileReader es similar a Java File.canread() ?

¿Podría alguien sugerir sobre esto? Tengo IE11 para probar el código.


El objeto FileReader permite que las aplicaciones web lean de forma asíncrona el contenido de los archivos (o memorias intermedias de datos sin procesar) almacenados en la computadora del usuario, utilizando objetos File o Blob para especificar el archivo o los datos a leer.

Los objetos de archivo se pueden obtener de un objeto FileList devuelto como resultado de que un usuario seleccione archivos usando el elemento, del objeto DataTransfer de una operación de arrastrar y soltar, o de la API mozGetAsFile () en un HTMLCanvasElement.

El método readAsText se usa para leer el contenido del Blob o Archivo especificado. Cuando se completa la operación de lectura, readyState se cambia a DONE, se activa el loadend y el atributo de resultado contiene el contenido del archivo como una cadena de texto.

Sintaxis

instanceOfFileReader.readAsText(blob[, encoding]);

Parámetros

Gota

El blob o archivo desde el que leer.

codificación opcional

Una cadena que especifica la codificación a usar para los datos devueltos. Por defecto, se supone UTF-8 si este parámetro no se especifica.

Para los metadatos sobre un archivo, podemos verificar el objeto Archivo F manera que: F tenga un estado de legibilidad de ABIERTO. F se refiere a la secuencia de bytes de bytes. F.size se establece en el número total de bytes en bytes. F.name se establece en n. F.type se establece en t.

Nota: El tipo t de un archivo se considera un tipo MIME analizable si la cadena codificada en ASCII que representa el tipo de objeto del archivo, cuando se convierte en una secuencia de bytes, no regresa indefinida para el algoritmo de tipo MIME analizado [MIMESNIFF].

F.lastModified se establece en d.

Vea más sobre compatibilidad del navegador y documentos detallados para FileReader , File y readAsText en MDN, también este borrador del W3C para FileApi


FileReader evento de load FileReader establece el valor .result forma asincrónica. Para acceder al .result use load o loadend event.

Cuando se ha seleccionado un archivo en <input type="file"> Choose File o Browse... UI, eliminar el archivo en el sistema de archivos local no debería afectar el objeto File en FileList devuelto por la llamada .files . Ver 2.9.2. Objetos transferibles , 6.7.3 La interfaz DataTransfer .

4. La interfaz de blob y los datos binarios

Cada Blob debe tener un estado de instantánea interno, que debe establecerse inicialmente en el estado del almacenamiento subyacente, si existe dicho almacenamiento subyacente, y debe conservarse mediante structured clone . Se puede encontrar una definición normativa adicional del snapshot state de la snapshot state para los File .

2.9.8 Parche de mono para objetos Blob y FileList

Este parche de mono se eliminará a su debido tiempo. Ver w3c / FileAPI número 32 .

Blob objetos Blob son cloneable objects .

  1. El método interno [[ Clone ]] de cada objeto Blob , dado targetRealm e ignorando la memoria, debe ejecutar estos pasos:

  2. Si esto está closed , arroje una "DataCloneError" DOMException "DataCloneError" .

Devuelve una nueva instancia de esto en targetRealm , correspondiente a los mismos datos subyacentes.

FileList objetos FileList son objetos clonables .

El método interno de cada objeto FileList [[Clone]] , dado targetRealm y memoria , debe ejecutar estos pasos:

  1. Deje que la salida sea ​​un nuevo objeto FileList en targetRealm .

  2. Para cada archivo en este , agregue? [StructuredClone][15](_file, targetRealm, memory_) al final de la lista de objetos File de salida .

Salida de retorno.

Selección de archivos o carpetas de solo lectura en los navegadores webkit y firefox

En Chrome, Chrome si el permiso de solo lectura se establece para el archivo en el sistema de archivos local y el usuario selecciona el archivo en el elemento <input type="file"> , donde FileReader se usa para leer el archivo, se genera un error en FileReader , generado a partir del progress FileReader evento.

Si una Blob URL se establece en el mismo objeto de archivo, blob: URL no devolverá el archivo de solo lectura cuando se solicite a la Blob URL .

Selección de carpeta donde el permiso de carpeta se establece en solo lectura

Cromo, cromo

En Chrome, el cromo donde se webkitdirectory atributo webkitdirectory y se selecciona la carpeta con permiso de solo lectura FileList .length of event.target.files devuelto 0 ; event.target.files.webkitGetAsEntry() no se llama, "No file chosen" se representa en <input type="file"> shadowDOM . Cuando una carpeta se cae en <input type="file"> o elemento donde se establece el atributo .path , el directorio .name y .path de la carpeta de solo lectura se muestra en drop event.dataTransfer .

Cuando el usuario suelta el archivo o la carpeta en el elemento <textarea> , donde no se adjunta ningún evento de drop que se beforeunload evento de beforeunload y se muestra un indicador en la interfaz de usuario

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

Firefox

En firefox versión 47.0b9 con el atributo allowdirs se establece en el elemento <input type="file"> , donde el usuario hace clic en "Choose folder.." <input> , la carpeta .name y .path de la carpeta principal están accesibles en .then() encadenado a event.target.getFilesAndDirectories() . Los archivos o carpetas contenidos en la carpeta seleccionada no se devuelven al iterar recursivamente las entradas del Directory ; Se devuelve una cadena vacía.

Si el usuario hace clic en "Choose file..." <input> y se selecciona una carpeta sin un conjunto de permisos de solo lectura, cuando se hace clic en la carpeta del administrador de archivos, se enumeran los archivos de la carpeta.

Cuando se selecciona una carpeta donde se configura el permiso de solo lectura, se muestra una notificación de alert() en la IU que se muestra

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

Error, problema de seguridad

* sistema operativo nix

Cuando el usuario suelta la carpeta en el elemento <textarea> , donde no se adjunta ningún evento de drop , la ruta completa a la carpeta en el file: sistema de file: usuario file: protocolo queda expuesto. Las rutas a los archivos contenidos dentro de la carpeta no se configuran también como .value ; p.ej,

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

Cuando se drop un archivo en el elemento <textarea> , donde se adjunta el evento no drop , la ruta completa al archivo en el sistema de archivos del usuario se establece como .value de <textarea> ; es decir,

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

Si se seleccionan varios archivos y se sueltan en el elemento <textarea> , todas las rutas de archivos completas se establecen como .value de <textarea> , delineadas por el nuevo carácter de línea /n

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

Donde se realiza un XMLHttpRequest() para la ruta del archivo y el error se registra en la console

NS_ERROR_DOM_BAD_URI: Access to restricted URI denied

Cuando se establece como .src de un elemento <img> con .crossOrigin establecido en "anonymous" se llama al controlador de eventos de error img

En la llamada a window.open() con la ruta completa establecida en el primer parámetro

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

Especificación

4.10.5.1.18. Estado de carga de archivo ( type=file )

EJEMPLO 16

Por razones históricas, el value atributo IDL antepone el nombre del archivo con la cadena " C:/fakepath/ ". Algunos agentes de usuario heredados en realidad incluían la ruta completa (que era una vulnerabilidad de seguridad). Como resultado de esto, obtener el nombre del archivo del atributo IDL de value de una manera compatible con versiones anteriores no es trivial.

4.10.5.4. API de elementos <input> comunes

nombre del archivo

Al obtener, debe devolver la cadena "C: / fakepath /" seguida del nombre del primer archivo en la lista de selected files , si corresponde, o la cadena vacía si la lista está vacía. En la configuración, si el nuevo valor es la cadena vacía, debe vaciar la lista de selected files ; de lo contrario, debe arrojar una InvalidStateError " DOMException ".

NOTA: Este requisito de "ruta falsa" es un triste accidente de la historia. Consulte el ejemplo en la sección Estado de carga de archivos para obtener más información.

NOTA: Dado path components no están permitidos en los nombres de archivo en la lista de selected files , " /fakepath/ " no puede confundirse con un componente de ruta.

4.10.5.1.18. Estado de carga de archivo ( type=file )

Componentes de la ruta

Cuando el atributo de type de un elemento <input> está en el estado de File Upload , se aplican las reglas de esta sección.

El elemento <input> represents una lista de selected files , cada archivo consta de un nombre de archivo, un tipo de archivo y un cuerpo de archivo (el contenido del archivo).

Los nombres de archivo no deben contener path components , incluso en el caso de que un usuario haya seleccionado una jerarquía de directorio completa o varios archivos con el mismo nombre de diferentes directorios. Los componentes de ruta , a los efectos del estado de File Upload , son aquellas partes de los nombres de archivo que están separadas por caracteres U + 005C REVERSE SOLIDUS character ().

Informe de error https://bugzilla.mozilla.org/show_bug.cgi?id=1311823

Colocar el archivo en <textarea> en el URI de datos

Siguiente comentario de Neal Deakin en el informe de error

Creo que los pasos mencionados son:

  1. Datos abiertos: texto / html,
  2. Arrastre un archivo desde el escritorio al área de texto

Puedo reproducir esto en Linux, pero no en Windows o Mac.

La corazonada de arriba es correcta; Linux también incluye los datos como una url y texto sin formato.

archivos caídos en los data: data URI prototcol en firefox y cromo, cromo

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

Firefox

El nombre de ruta completo del archivo o carpeta establecido como .value de <textarea> .

Cromo, cromo

Al soltar el archivo en data URI tiene solo un elemento de área de textarea en Chrome, el cromo reemplaza el data URI con la ruta del archivo en la barra de direcciones y carga el archivo en la misma pestaña, reemplazando el data URI con el contenido del archivo.

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

html , javascript para reproducir el problema descrito anteriormente

<!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

Puede usar el evento de change adjunto al elemento #myfile para manejar la acción de selección de archivos por usuario.

Sustituya el elemento <textarea> por el elemento <p> para mostrar el resultado del evento de load de la llamada .readAsText() .

Para mostrar .result de FileReader al click en el elemento del button , establezca el text variable en reader.result dentro del evento de load de FileReader al click evento al configurar el button .textContent del elemento #DisplayText para hacer referencia a variables que establecieron anteriormente 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>