#javascript #html #drag-and-drop #textarea #fileapi
#javascript #HTML #перетаскивание #текстовая область #fileapi
Вопрос:
Я написал следующий код, чтобы проверить, существует ли загруженный файл или нет, используя HTML5 file 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()
. После нажатия кнопки я все еще мог видеть, что Filereader.result
не равно нулю, и мог отображать все содержимое.
Может кто-нибудь объяснить, как работает Filereader? Связано ли это с тем, что FileReader привязывается при просмотре файла?
Также можем ли мы проверить, похож ли системный атрибут только для чтения с FileReader на Java File.canread()
?
Может кто-нибудь предложить по этому поводу? У меня есть IE11 для тестирования кода.
Ответ №1:
FileReader
load
событие устанавливает .result
значение асинхронно. Для доступа к событию .result
use load
или loadend
.
Когда файл был выбран в <input type="file">
Choose File
или Browse...
пользовательском интерфейсе, удаление файла в локальной файловой системе не должно влиять на File
объект, FileList
возвращаемый .files
вызовом. Смотрите 2.9.2. Передаваемые объекты, 6.7.3 Интерфейс передачи данных.
4. Интерфейс Blob и двоичные данные
У каждого
Blob
должно быть внутреннее состояние моментального снимка, которое должно быть изначально установлено в состояние базового хранилища, если такое базовое хранилище существует, и должно быть сохранено черезstructured clone
. Дляsnapshot state
s можно найти дополнительное нормативное определениеFile
.
2.9.8 Обезьяний патч для объектов Blob и FileList
Этот патч обезьяны будет удален в свое время. Смотрите выпуск 32 w3c / FileAPI.
Blob
объекты являютсяcloneable objects
.
Внутренний метод каждого
Blob
объекта [[Clone
]], задающий targetRealm и игнорирующий память, должен выполнять эти шаги:Если это так
closed
, то бросьте"DataCloneError"
DOMException
.Верните новый экземпляр этого в targetRealm, соответствующий тем же базовым данным.
FileList
объекты являются клонируемыми объектами.Внутренний метод каждого
FileList
объекта[[Clone]]
, учитывая targetRealm и память, должен выполнять эти шаги:
Пусть выводом будет новый
FileList
объект в targetRealm.Для каждого файла в этом, добавить ?
[StructuredClone][15](_file, targetRealm, memory_)
в конец спискаFile
объектов вывода.Возвращает вывод.
Выбор файлов или папок, доступных только для чтения, в браузерах 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.
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
.
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
; event.target.files.webkitGetAsEntry()
is not called, "No file chosen"
is rendered at <input type="file">
shadowDOM
. 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
.
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
Do you want to leave this site? Changes you made may not be saved. <Stay><Leave> // <buttons>
Firefox
В Firefox версии 47.0b9 с allowdirs
атрибутом установлен в <input type="file">
элементе, на который пользователь нажимает "Choose folder.."
<input>
, папка .name
и .path
родительская папка доступны по адресу .then()
привязаны к event.target.getFilesAndDirectories()
. Файлы или папки, содержащиеся в выбранной папке, не возвращаются при рекурсивном повторении Directory
записей; возвращается пустая строка.
Если пользователь нажимает "Choose file..."
<input>
и выбрана папка без установленного разрешения только для чтения, при нажатии на папку в файловом менеджере отображаются файлы в папке.
Если выбрана папка, в которой установлено разрешение только для чтения, alert()
уведомление отображается при отображении пользовательского интерфейса
Could not read the contents of <directory name> Permission denied
Ошибка, проблема безопасности
* Операционная система nix
Когда пользователь удаляет папку на <textarea>
элементе, к которому не прикреплено ни одно drop
событие, отображается полный путь к папке по протоколу пользовательской файловой системы file:
. Пути к файлам, содержащимся в папке, также не заданы как .value
; например,
"file:///home/user/Documents/Document/"
Когда файл удаляется из <textarea>
элемента, к которому прикреплено событие not 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
Когда задано как .src
для <img>
элемента с .crossOrigin
значением, равным "anonymous"
, вызывается обработчик событий img
error
При вызове window.open()
с полным путем, установленным в первом параметре
Error: Access to '"file:///home/user/Documents/Document/MyFileFullPathDisplayedAtTextAreaValue.png"' from script denied
Спецификация
4.10.5.1.18. Состояние загрузки файла ( type=file
)
По историческим причинам
value
атрибут IDL добавляет к имени файла строку «C:fakepath
«. Некоторые устаревшие пользовательские агенты фактически включали полный путь (что было уязвимостью системы безопасности). В результате этого получение имени файла изvalue
атрибута IDL обратно совместимым способом является нетривиальным.
4.10.5.4. API-интерфейсы общих <input>
элементов
имя файла
При получении он должен возвращать строку «C:fakepath » за которым следует имя первого файла в списке
selected
, если таковой имеется, или пустая строка, если список пуст. При настройке, если новое значение является пустой строкой, оно должно очистить список
filesselected files
; в противном случае оно должно выдавать «InvalidStateError
»DOMException
.ПРИМЕЧАНИЕ: Это требование «поддельного пути» является печальной случайностью истории. Смотрите пример в разделе Состояние загрузки файла для получения дополнительной информации.
ПРИМЕЧАНИЕ: Поскольку
path components
имена файлов в спискеselected files
не разрешены, «fakepath
» нельзя ошибочно принять за компонент path.
4.10.5.1.18. Состояние загрузки файла ( type=file
)
Компоненты пути
Когда
<input>
атрибутtype
элемента находится вFile Upload
состоянии, применяются правила этого раздела.
<input>
Элементrepresents
представляет собой списокselected files
, каждый файл состоит из имени файла, типа файла и тела файла (содержимого файла).Имена файлов не должны содержать
path components
даже в том случае, если пользователь выбрал целую иерархию каталогов или несколько файлов с одинаковым именем из разных каталогов. Компонентами пути для целейFile Upload
состояния являются те части имен файлов, которые разделены символами ОБРАТНОГО солидуса U 005C ().
Сообщение об ошибке https://bugzilla.mozilla.org/show_bug.cgi?id=1311823
Удаление файла в <textarea> в URI данных
Следующий комментарий Нила Дикина к сообщению об ошибке
Я думаю, что упомянутые шаги:
- Открытые данные: текст / html,
- Перетащите файл с рабочего стола в текстовую область
Я могу воспроизвести это в Linux, но не в Windows или Mac.
Приведенная выше догадка верна; Linux также включает данные в виде URL и открытого текста.
dropped files at data:
prototcol data URI
at firefox, and chrome, chromium
data:text/html,<textarea></textarea>
Firefox
The full path name of file or folder set as .value
of <textarea>
.
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.
plnkr http://plnkr.co/edit/ZfAGEAiyLLq8rGXD2ShE?p=preview
html
, javascript
to reproduce issue described above
<!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 amp;amp; 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
Вы можете использовать change
событие, прикрепленное к #myfile
элементу, для обработки действий пользователя по выбору файла.
Замените <textarea>
элемент на <p>
элемент, чтобы отобразить результат load
события из .readAsText()
вызова.
Для отображения .result
элемента FileReader
click
at button
, установите переменную text
в reader.result
значение load
в FileReader
событии click
at button
event при .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>
Комментарии:
1. @sushmithaP Смотрите 2.9.8 Monkey patch для объектов Blob и FileList , File API
2. Спасибо за ответ. Но в дополнение к этому, как удаление файла в локальной файловой системе после просмотра и перед adddoc() не влияет на reader.result. Создает ли это какой-либо кеш?
3.@sushmithaP В
html
<input type="file">
элементеid
есть"myfile"
, наjavascript
который вы ссылаетесь#myFile
, который не отображается вhtml
вопросе. Кроме того, используйтеchange
событие, прикрепленное к<input type="file">
элементу, для обработки файла, выбранного из локальной файловой системы.4. @sushmithaP обнаружил ошибку в Firefox, из-за которой файлы удалялись из
<textarea>
наборов элементов.value
<textarea>
для заполнения пути к файлу в локальной файловой системе.
Ответ №2:
Объект FileReader позволяет веб-приложениям асинхронно считывать содержимое файлов (или буферов необработанных данных), хранящихся на компьютере пользователя, используя объекты File или Blob для указания файла или данных для чтения.
Файловые объекты могут быть получены из объекта FileList, возвращаемого в результате выбора пользователем файлов с помощью элемента, из объекта dataTransfer операции перетаскивания или из mozGetAsFile() API в HTMLCanvasElement.
Метод readAsText используется для чтения содержимого указанного большого двоичного объекта или файла. Когда операция чтения завершена, readyState изменяется на DONE, запускается loadend, а атрибут result содержит содержимое файла в виде текстовой строки.
Синтаксис
instanceOfFileReader.readAsText(blob[, encoding]);
Параметры
Большой двоичный объект
Большой двоичный объект или файл, из которого нужно читать.
кодировка необязательна
Строка, указывающая кодировку, которую следует использовать для возвращаемых данных. По умолчанию предполагается UTF-8, если этот параметр не указан.
Для метаданных о файле мы можем проверить объект File F
таким образом, что: F имеет состояние читаемости OPEN. F относится к последовательности байтов. F.size
устанавливается на общее количество байтов в байтах. F.name
имеет значение n. F.type
имеет значение t.
Примечание: Тип t файла считается анализируемым типом MIME, если строка в кодировке ASCII, представляющая тип файлового объекта, при преобразовании в последовательность байтов не возвращает значение undefined для алгоритма синтаксического анализа типа MIME [MIMESNIFF].
F.lastModified
имеет значение d.
Смотрите больше о совместимости с браузерами и подробном документе для FileReader, File и readAsText в MDN, а также этот проект W3C для FileAPI
Комментарии:
1. Как вы отвечаете на адресные вопросы, представленные в OP «Происходит ли так, что программа чтения файлов привязывается при просмотре файла? Также можем ли мы проверить, похож ли системный атрибут FileReader только для чтения с FileReader на Java File.canread()?» ?
2. добавлены все доступные атрибуты файла, как указано в w3c, но по-прежнему доступно только для чтения
3. Вы пробовали читать файл или папку, для которых в файловой системе установлено разрешение только для чтения? «добавлены все доступные атрибуты файла, как указано в w3c, но по-прежнему доступно только для чтения» Это часть вопроса. Ваш ответ не касается этой части вопроса или этих вопросов «После просмотра файла из локальной системы я попытался удалить «просмотренный» документ из папки, прежде чем нажать addDoc(). После нажатия кнопки я все еще мог видеть, что Filereader.result не равен нулю и может отображать все содержимое.» .
4. @guest271314 Я пробовал файлы с разрешением только для чтения, проверьте демонстрацию woking на html5rocks.com/en/tutorials/file/dndfiles . В этой демонстрации показаны все доступные параметры и атрибуты из файла. Я смог не только читать, но и разделять файлы «Только для чтения». Файлы фактически реплицируются во временном каталоге браузера перед загрузкой в виде данных формы из нескольких частей, и вам разрешено читать файлы «Только для чтения», мы не можем просто перезаписать или изменить их
5. «Я пробовал файлы с разрешением только для чтения, проверьте демонстрацию woking на html5rocks.com/en/tutorials/file/dndfiles . Эта демонстрация показывает все доступные параметры и атрибуты из файла. Я смог не только прочитать, но и разделить файлы «Только для чтения». Файлы фактически реплицируются во временном каталоге браузера перед загрузкой в виде данных формы из нескольких частей, и вам разрешено читать файлы «Только для чтения», мы не можем просто перезаписать или изменить их » Интересно. Подумайте о том, чтобы поделиться тем, что вы нашли, с описанием того, как воспроизвести на bugzilla.mozilla.org/show_bug.cgi?id=1311823
Ответ №3:
Используйте это вместо:-
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>