将参数传递给FileReader的onload事件

25

我需要读取用户提供的一些csv文件。通过拖放div将文件传递给页面/脚本,处理文件拖放的方式如下:

function handleFileDrop(evt) {
    evt.stopPropagation();
    evt.preventDefault();
    var files = evt.dataTransfer.files; // FileList object.
    ...
}

我需要使用一个csv库来解析每个文件并将其转换为数组,但我还需要跟踪我当前解析的文件名。以下是我用来解析每个文件的代码:

for(var x = 0; x < files.length; x++){
    var currFile = files[x];
    var fileName = currFile.name;
    var reader = new FileReader();
    reader.onload = (function(theFile){
        return function(e){
            var csvArr = CSV.csvToArray( e.target.result, ";", true );
            console.log(csvArr); 
        };
    })(currFile);   
    reader.readAsText(currFile);
}

到目前为止,一切都很顺利。我需要将文件名传递给reader.onload事件,例如:

reader.onload = (function(theFile){
    return function(e){

       ***** I need to have fileName value HERE *****

    };
})(currFile); 

这是可能的吗?我该如何做到这一点?非常感谢您提前的帮助,此致敬礼。
2个回答

56

请尝试以下方法:

var reader = new FileReader();
reader.onload = (function(theFile){
    var fileName = theFile.name;
    return function(e){
        console.log(fileName);
        console.log(e.target.result);
    };
})(currFile);   
reader.readAsText(currFile);

在这里,每当一个文件传递给外部方法时,您都会创建一个新的fileName变量。 然后,您创建了一个可以访问该变量的函数(由于闭包),并将其返回。


4
怎样才能同时获取文件名和读取器(reader)的结果(result)值? - PatriceG
我在跟代码时遇到了困难,'theFile' 是从哪里来的?我能看出 currFile 定义在哪里,但是 'theFile' 代表什么? - NiallJG
1
@NiallJG 如果您查看分配给 onload 属性的内容,实际上我们正在执行一个函数并传递 currFile。在该函数内部,theFile 只是我们传入的文件的另一个名称。这使我们能够存储对该文件名称的引用,一旦实际读取文件内容就可以访问它。 - Graham
1
@John 内部函数是一个闭包,因为它在返回后仍保留对 fileName 变量的引用。你看到的语法通常被称为立即调用函数表达式,简称 IIFE。 - Graham
1
如果您有一个文件数组,并且正在按顺序读取它们,那么采用不同的方法创建一个计数器变量来引用当前数组索引可能会更好。然后,您只需要一个onload就可以访问原始文件数组,因此可以访问名称。请参见https://codepen.io/anon/pen/jdXJRY?editors=1011作为基本示例。如果文件很大,则可以考虑为每个文件使用FileReader并在Workers内部读取它们以避免锁定浏览器。 - Graham
显示剩余5条评论

2

使用 Blob API

使用 新的 File / Blob API 可以更加轻松地实现。

你的第二个代码块 - 同样解决了你的问题 - 可以改写为:

for (let file of files){
 (new Blob([file])).text().then(x=>console.log(file.name,x));
}

Blob API使用Promise而非像Filereader API那样使用事件,因此避免了闭包的许多问题。另外箭头函数(x=>)迭代器for of使代码更加简洁。
请查看支持情况

使用Fetch API

同时使用Fetch API响应对象可以更轻松地完成。
for (let file of files){
 (new Response(file)).text().then(x=>console.log(file.name,x));
}

构造函数中缺少Array []的注意事项。

此外检查支持


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接