如何使用Javascript读取本地文本文件并逐行读取?

98

我有一个由html+javascript制作的网页,这是一个演示页面。我想知道如何读取本地csv文件并逐行读取,以便从csv文件中提取数据。


2
看这个http://www.html5rocks.com/en/tutorials/file/dndfiles/ - Hunter Larco
2
您是否有任何浏览器兼容性要求?特别是,您是否支持IE9或更低版本? - undefined
@Derek,仍然有一個問題,如何逐行獲取內容,因為readAsText似乎會返回所有數據。 - litaoshen
@litaoshen - 这里有一个相关的帖子,可能可以回答你的问题:http://stackoverflow.com/questions/9917246/how-do-you-read-parse-a-text-file-line-by-line-using-html-javascript?rq=1 - Derek 朕會功夫
一个更好的测试和更高质量的解决方案在https://dev59.com/p2Af5IYBdhLWcg3wbSUi。@Derek:不,你提到的那个答案没有帮助。 - Dan Dascalescu
显示剩余5条评论
3个回答

136

没有jQuery:

const $output = document.getElementById('output')
document.getElementById('file').onchange = function() {
  var file = this.files[0];

  var reader = new FileReader();
  reader.onload = function(progressEvent) {
    // Entire file
    const text = this.result;
    $output.innerText = text

    // By lines
    var lines = text.split('\n');
    for (var line = 0; line < lines.length; line++) {
      console.log(lines[line]);
    }
  };
  reader.readAsText(file);
};
<input type="file" name="file" id="file">
<div id='output'>
  ...
</div>

记得在文件字段渲染后放置您的 JavaScript 代码。


33
我有20万行的日志文件(不是玩笑),我认为你的解决方案无法覆盖那么多行,但还是谢谢尝试。 - Tomáš Zato
此解决方案还无法处理返回(换行)位于引号字段内的情况。至于Tomas,如果你使用更高级的浏览器,你可以使用生成器逐行读取而不需要进行“拆分”。 - Rahly
8
外部文件的路径在哪里,我们从中获取行? - abidinberkay
2
@gsamaras 我不记得具体是哪个流,但我使用了一些逐块读取数据的流,并在每次遇到 \n 时发出事件。但是对于100m行,你会遇到在HTML中显示它们的表格问题。 - Tomáš Zato
@TomášZato-ReinstateMonica 实际上,我刚刚在一个超过60,000,000行的文件上运行了这个脚本,而且运行非常顺利 :) 最耗时的部分是上传。 - zessx
显示剩余4条评论

46

使用ES6,JavaScript会变得更加简洁。

handleFiles(input) {

    const file = input.target.files[0];
    const reader = new FileReader();

    reader.onload = (event) => {
        const file = event.target.result;
        const allLines = file.split(/\r\n|\n/);
        // Reading line by line
        allLines.forEach((line) => {
            console.log(line);
        });
    };

    reader.onerror = (event) => {
        alert(event.target.error.name);
    };

    reader.readAsText(file);
}

5
投票支持使用正则表达式拆分行,这是正确的方式。 - Meysam Feghhi
17
更简单的正则表达式:\r?\n - ceving
3
非常好的例子,我喜欢它处理Windows和Unix风格的换行符。谢谢。 - Brad
6
const allLines = file.split(/\r\n|\n/); - 这并不是真正的“逐行读取”。这是一次性读取整个多GB文件,导致程序崩溃。 - Ark-kun
1
@Ark-kun,确实,那么该如何解决呢? - mke21
@mke21 请查看此答案:https://dev59.com/-MTra4cB1Zd3GeqP1TyD#71983228 - Ark-kun

0
这是一个来自MDN文档的函数,它展示了如何使用ReadableStream逐行读取文件。这个例子使用了fetch,但如果你已经有了一个File,你可以调用stream()getReader()来代替。
async function* makeTextFileLineIterator(fileURL) {
  const utf8Decoder = new TextDecoder("utf-8");
  let response = await fetch(fileURL);
  let reader = response.body.getReader();
  let { value: chunk, done: readerDone } = await reader.read();
  chunk = chunk ? utf8Decoder.decode(chunk, { stream: true }) : "";

  let re = /\r\n|\n|\r/gm;
  let startIndex = 0;

  for (;;) {
    let result = re.exec(chunk);
    if (!result) {
      if (readerDone) {
        break;
      }
      let remainder = chunk.substr(startIndex);
      ({ value: chunk, done: readerDone } = await reader.read());
      chunk =
        remainder + (chunk ? utf8Decoder.decode(chunk, { stream: true }) : "");
      startIndex = re.lastIndex = 0;
      continue;
    }
    yield chunk.substring(startIndex, result.index);
    startIndex = re.lastIndex;
  }
  if (startIndex < chunk.length) {
    // last line didn't end in a newline char
    yield chunk.substr(startIndex);
  }
}

for await (let line of makeTextFileLineIterator(urlOfFile)) {
  processLine(line);
}

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