如何使用JavaScript读取任何本地文件?

时间:2018-05-09 13:23:51

标签: javascript html performance file filereader

如何通过块(2kb或更多)在本地读取任何大文件(大于1千兆字节),然后将块转换为字符串,处理字符串然后获取下一个块,依此类推,直到结束文件?

我只能读取小文件并将其转换为字符串,您可以从代码中看到我不知道如何通过块读取文件。如果我尝试使用大于10mb的文件,浏览器会冻结。

<html>
  <head>
    <title>Read File</title>
  </head>

  <body>
    <input type="file" id="myFile">
    <hr>
    <textarea style="width:500px;height: 400px" id="output"></textarea>

    <script>
      var input = document.getElementById("myFile");
      var output = document.getElementById("output");
      input.addEventListener("change", function () {
        if (this.files && this.files[0]) {
          var myFile = this.files[0];
          var reader = new FileReader();
          reader.addEventListener('load', function (e) {
            output.textContent = e.target.result;
          });
          reader.readAsBinaryString(myFile);
        }
      });
    </script>

  </body>
</html>

以下是我在StackOverflow上发现的链接和答案,同时研究如何完成它,但它并没有解决我的问题。

  

1:这个问题是询问如何使用UniversalXPConnect进行,只有在Firefox中,这就是为什么我发现那里的答案无关紧要,因为我使用的是Chrome并且不在知道UniversalXPConnect是什么。   How to read a local file by chunks in JavaScript

     

2:这个问题只是询问如何阅读文本文件,但我希望能够读取任何文件,不仅仅是文本,也可以读取块,这使得答案无关紧要,但我喜欢答案的代码有多短。 Reading local text file into a JavaScript array [duplicate]

     

3:这也是关于文本文件的,并没有显示如何按块How to read a local text file.

读取文件

我知道一点Java,你可以很容易地做到这一点;

char[] myBuffer = new char[512];
int bytesRead = 0;
BufferedReader in = new BufferedReader(new FileReader("foo.mp4"));
while ((bytesRead = in.read(myBuffer,0,512)) != -1){
...
}

但我是javascript新手

3 个答案:

答案 0 :(得分:0)

所以问题不在于FileReader,而在于:

output.textContent = e.target.result;

因为您试图一次性将10 MB +的字符串转储到textarea。我甚至不确定是否有一种“正确”的方式来做你想要的事情,因为即使你确实拥有了它,它仍然必须在每个循环中通过那些汇总output.textContent的先前值块,所以当它接近结束时,它会以相同的方式开始减速(更糟糕的是,真的,因为它会在每个循环上做慢速内存占用业务)。所以我认为部分循环过程必须添加一个新元素(比如新的textarea来推送当前的块(因此它不需要进行任何连接来保留已经存在的内容)我还没有完成那部分工作,但到目前为止我已经完成了这件事:

  var input = document.getElementById("myFile");
  var output = document.getElementById("output");
  var chunk_length = 2048; //2KB as you mentioned
  var chunker = new RegExp('[^]{1,' + chunk_length + '}', 'g');
  var chunked_results;

  input.addEventListener("change", function () {
    if (this.files && this.files[0]) {
      var myFile = this.files[0];
      var reader = new FileReader();
      reader.addEventListener('load', function (e) {
        chunked_results = e.target.result.match(chunker);
        output.textContent = chunked_results[0];
      });
      reader.readAsBinaryString(myFile);
    }
  });

这只是输出2KB块数组中的第一个字符串。你想做的就是在DOM文档中添加一个新的元素/节点来输出所有其他的块。

使用RegExpmatch进行实际分块是从我找到的clever gist中解除的。

答案 1 :(得分:0)

我能够通过指定文件的切片来解决它,通过指定切片的开始位置以及将要结束的块的位置,然后将其包含在while循环中,以便每个循环块位置将根据到文件末尾所需的块大小。

但是在运行之后,我最终得到了文本区域中块的最后一个值,所以要显示所有二进制字符串,我会在每次迭代时连接输出。

<html>
<head>
  <title>Read File</title>
</head>

<body>
  <input type="file" id="myFile">
  <hr>
  <textarea style="width:500px;height: 400px" id="output"></textarea>

  <script>
    var input = document.getElementById("myFile");
    var output = document.getElementById("output");
    var chunk_size = 2048;
    var offset = 0;
    input.addEventListener("change", function () {
      if (this.files && this.files[0]) {
        var myFile = this.files[0];
        var size = myFile.size; //getting the file size so that we can use it for loop statement
        var i=0;
        while( i<size){
        var blob = myFile.slice(offset, offset + chunk_size); //slice the file by specifying the index(chunk size)
        var reader = new FileReader();
        reader.addEventListener('load', function (e) {
          output.textContent += e.target.result; //concatenate the output on each iteration.
        });
        reader.readAsBinaryString(blob);
        offset += chunk_size; // Increment the index position(chunk) 
        i += chunk_size; // Keeping track of when to exit, by incrementing till we reach file size(end of file).
        }
      }
    });
  </script>

</body>
</html>

答案 2 :(得分:-1)

您可以使用fs.createReadStream()执行此操作,可能缓冲的数据量取决于传递给流构造函数的highWaterMark选项。 所以你会这样做:

var read = fs.createReadStream(&#39; / something / something&#39;,{highWaterMark:64});

这是一个例子:

var fs = require('fs')
var read = fs.createReadStream('readfile.txt',{highWaterMark:64}) 
var write = fs.createWriteStream('written.txt')
read.on('open', function () {
    read.pipe(write);
});

看看它一次读取64个字节(非常慢),你可以用有趣的方式在资源管理器上查看它,但要确保你有一个大文本文件来测试它不是一个千兆字节,但至少有17兆字节像我一样做了#34;填写任何虚拟文本&#34; 将文件视图设为&#34;详细信息&#34;并在Windows资源管理器中不断刷新目标,每次刷新时都会看到大小增加。

如果你没有问题,我假设你知道管道方法!它非常简单,这里有一个链接: https://nodejs.org/api/stream.html#stream_readable_pipe_destination_options

或快速解释: readable.pipe(writable)   pipe()函数在可读流可用时读取数据并将其写入目标可写流。