我正在使用 FileReader API来读取多个文件。
<html> <body>
<input type="file" id="filesx" name="filesx[]"
onchange="readmultifiles(this.files)" multiple=""/>
<div id="bag"><ul/></div>
<script>
window.onload = function() {
if (typeof window.FileReader !== 'function') {
alert("The file API isn't supported on this browser yet.");
}
}
function readmultifiles(files) {
var ul = document.querySelector("#bag>ul");
while (ul.hasChildNodes()) {
ul.removeChild(ul.firstChild);
}
function setup_reader(file) {
var name = file.name;
var reader = new FileReader();
reader.onload = function(e) {
var bin = e.target.result; //get file content
// do sth with text
var li = document.createElement("li");
li.innerHTML = name;
ul.appendChild(li);
}
reader.readAsBinaryString(file);
}
for (var i = 0; i < files.length; i++) { setup_reader(files[i]); }
}
</script> </body> </html>
问题是所有文件都是同时读取的,当文件的总大小(总和)非常大时,浏览器会崩溃。
我想一个接一个地读取一个文件,以便减少内存消耗。
这可能吗?
答案 0 :(得分:17)
我自己想出了一个有效的解决方案。
function readmultifiles(files) {
var reader = new FileReader();
function readFile(index) {
if( index >= files.length ) return;
var file = files[index];
reader.onload = function(e) {
// get file content
var bin = e.target.result;
// do sth with bin
readFile(index+1)
}
reader.readAsBinaryString(file);
}
readFile(0);
}
答案 1 :(得分:15)
这应该逐个读取文件:
function readmultifiles(files) {
var ul = document.querySelector("#bag>ul");
while (ul.hasChildNodes()) {
ul.removeChild(ul.firstChild);
}
// Read first file
setup_reader(files, 0);
}
// Don't define functions in functions in functions, when possible.
function setup_reader(files, i) {
var file = files[i];
var name = file.name;
var reader = new FileReader();
reader.onload = function(e){
readerLoaded(e, files, i, name);
};
reader.readAsBinaryString(file);
// After reading, read the next file.
}
function readerLoaded(e, files, i, name) {
// get file content
var bin = e.target.result;
// do sth with text
var li = document.createElement("li");
li.innerHTML = name;
ul.appendChild(li);
// If there's a file left to load
if (i < files.length - 1) {
// Load the next file
setup_reader(files, i+1);
}
}
答案 2 :(得分:7)
我正在更新此问题,以便新用户正在寻找通过the FileReader API上传多个文件的解决方案,尤其是使用ES。
不是手动迭代每个文件,而是更简单和更简单。使用清洁工Object.keys(files)
in ES:
<input type="file" onChange="readmultifiles" multiple/>
<script>
function readmultifiles(e) {
const files = e.currentTarget.files;
Object.keys(files).forEach(i => {
const file = files[i];
const reader = new FileReader();
reader.onload = (e) => {
//server call for uploading or reading the files one-by-one
//by using 'reader.result' or 'file'
}
reader.readAsBinaryString(file);
})
};
</script>
答案 3 :(得分:1)
您必须为每个文件实例化一个FileReader 才能读取。
function readFiles(event) {
//Get the files
var files = event.input.files || [];
if (files.length) {
for (let index = 0; index < files.length; index++) {
//instantiate a FileReader for the current file to read
var reader = new FileReader();
reader.onload = function() {
var result = reader.result;
console.log(result); //File data
};
reader.readAsDataURL(files[index]);
}
}
}
答案 4 :(得分:1)
使用 multiple
属性定义输入:
<input onchange = 'upload(event)' type = 'file' multiple/>
定义上传函数:
const upload = async (event) => {
// Convert the FileList into an array and iterate
let files = Array.from(event.target.files).map(file => {
// Define a new file reader
let reader = new FileReader();
// Create a new promise
return new Promise(resolve => {
// Resolve the promise after reading file
reader.onload = () => resolve(reader.result);
// Read the file as a text
reader.readAsText(file);
});
});
// At this point you'll have an array of results
let res = await Promise.all(files);
}
答案 5 :(得分:0)
我的完整解决方案在这里:
<html> <body>
<input type="file" id="filesx" name="filesx[]"
onchange="readmultifiles(this.files)" multiple=""/>
<div id="bag"></div>
<script>
window.onload = function() {
if (typeof window.FileReader !== 'function') {
alert("The file API isn't supported on this browser yet.");
}
}
function readmultifiles(files) {
var reader = new FileReader();
function readFile(index) {
if( index >= files.length ) return;
var file = files[index];
reader.onload = function(e) {
// get file content
var bin = e.target.result;
// do sth with bin
readFile(index+1)
}
reader.readAsBinaryString(file);
}
readFile(0);
function setup_reader(file) {
var name = file.name;
var reader = new FileReader();
var ul = document.createElement("ul");
document.getElementById('bag').appendChild(ul);
reader.onload = function(e) {
var bin = e.target.result; //get file content
// do sth with text
var li = document.createElement("li");
li.innerHTML = name;
ul.appendChild(li);
}
reader.readAsBinaryString(file);
}
for (var i = 0; i < files.length; i++) { setup_reader(files[i]); }
}
</script> </body> </html>
答案 6 :(得分:0)
充分利用这些答案。
<input type="file" onchange="readmultifiles(this.files)" multiple />
<script>
function readmultifiles(files) {
for (file of files) {
const reader = new FileReader();
reader.readAsBinaryString(file);
reader.fileName = file.name;
reader.onload = (event) => {
const fileName = event.target.fileName;
const content = event.currentTarget.result;
console.log({ fileName, content });
};
}
}
</script>
答案 7 :(得分:0)
我使用现代JS(地图,迭代器)实现了另一个解决方案。我从Angular应用程序改编了代码(最初使用某些TS功能编写)。
就像提到史蒂夫·卡科(Steve KACOU)一样,我们为每个文件创建一个不同的FileReader实例。
<input type="file" id="filesx" name="filesx[]"
onchange="processFileChange(this)" multiple=""/>
function processFileChange(event) {
if (event.target.files && event.target.files.length) {
const fileMap = new Map();
for (let i = 0; i < event.target.files.length; i++) {
const file = event.target.files[i];
const fileReader = new FileReader();
fileMap.set(fileReader, file);
}
const mapEntries = fileMap.entries();
readFile(mapEntries);
}
}
readFile(mapEntries) {
const nextValue = mapEntries.next();
if (nextValue.done === true) {
return;
}
const [fileReader, file] = nextValue.value;
fileReader.readAsDataURL(file);
fileReader.onload = () => {
// Do black magic for each file here (using fileReader.result)
// Read the next file
readFile(mapEntries);
};
}
基本上,这利用了通过引用传递对象的方式来使地图在每次迭代中永存。我认为这使得代码非常容易阅读。