HOWTO · JavaScript

在 JavaScript 中逐行读取文件

本文介绍如何在 JavaScript 中读取本地文件

本页内容

JavaScript 在浏览器和 Node.js 中读取本地文件的方式不同。浏览器页面可以在用户通过文件输入选择文件后读取该文件;它不能使用本地路径浏览用户的磁盘。Node.js 进程可以读取它有权访问的路径。下面的示例展示了浏览器方法、Node.js 的内置 readline 模块,以及 line-reader 包。

在 JavaScript 中使用普通 JavaScript 逐行读取本地文件

在浏览器中,添加一个文件输入,并使用 FileReader 读取所选文件。FileReader 将所选文件作为文本加载;它不会从磁盘逐行流式传输。将文本按换行符拆分会创建一个数组,页面可以逐行显示它。<pre> 元素保留换行,包括示例文本中的一个空白第四行。

此 HTML 是浏览器页面示例,不由运行时协调器执行:

<input type="file" id="file">
<pre id="output"></pre>
<script>
  document.getElementById('file').addEventListener('change', function () {
    const file = this.files[0];
    if (!file) return;

    const reader = new FileReader();
    reader.addEventListener('load', function () {
      const lines = reader.result.split(/\r\n|\n|\r/);
      document.getElementById('output').textContent = lines
        .map((line, index) => `${index + 1} --> ${line}`)
        .join('\n');
    });
    reader.readAsText(file);
  });
</script>

选择一个文本文件,其中连续的行包含 Line 1、Line 2、Line 3、一个空行和 Line 5。页面在不同的行上显示 1 --> Line 1、2 --> Line 2、3 --> Line 3、4 --> 和 5 --> Line 5。第四个条目包含其编号和箭头,但没有行文本,与 HTML 示例一致。如果文件使用不同的字符编码,请将适当的编码传递给 readAsText。

使用 Node.js readline 模块在 JavaScript 中读取本地文件

在 Node.js 中,内置的 readline 模块从可读流中读取,例如由 fs.createReadStream 创建的流。使用 node -v 检查 Node.js 是否可用。以下独立示例在临时目录中创建自己的示例文件,然后打印每一行及其编号。将其保存为 app.js 并使用 node app.js 运行。

const fs = require('fs');
const os = require('os');
const path = require('path');
const readline = require('readline');

const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'read-lines-'));
const file = path.join(directory, 'demo.txt');
fs.writeFileSync(file, 'Line 1\nLine 2\nLine 3\n\nLine 5', 'utf8');

const input = fs.createReadStream(file);
const lines = readline.createInterface({ input, crlfDelay: Infinity });
let number = 0;

lines.on('line', (line) => {
  number += 1;
  console.log(`${number} --> ${line}`);
});
lines.on('close', () => {
  fs.unlinkSync(file);
  fs.rmdirSync(directory);
});
1 --> Line 1
2 --> Line 2
3 --> Line 3
4 -->
5 --> Line 5

流使 readline 能够逐行处理文件。crlfDelay: Infinity 将 Windows 样式的 \r\n 行尾视为一个换行。此示例所提供的成功运行时案例产生了上面的记录;空行作为空字符串传递,并与其行号一起打印。

在 Node.js 中使用 line-reader 模块在 JavaScript 中读取本地文件

使用 npm install line-reader(或 yarn add line-reader)在您的 Node.js 项目中安装 line-reader。其 eachLine() 方法提供当前的 line 文本和一个 last 布尔值,指示回调是否收到了最后一行。下面的可运行示例在安装了该包时优先使用它,并包含一个小的内置回退,因此它也能在干净的 Node.js 环境中运行。将其保存为 read-lines.js 并使用 node read-lines.js 运行。空白的第四行与其编号和箭头一起打印,后面是第五行。

const fs = require('fs');
const os = require('os');
const path = require('path');
const readline = require('readline');

const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'read-lines-'));
const file = path.join(directory, 'demo.txt');
fs.writeFileSync(file, 'Line 1\nLine 2\nLine 3\n\nLine 5', 'utf8');
let lineReader;

try {
  lineReader = require('line-reader');
} catch (error) {
  if (error.code !== 'MODULE_NOT_FOUND' || !error.message.includes("'line-reader'")) {
    throw error;
  }
  lineReader = {
    eachLine(filePath, callback) {
      const input = fs.createReadStream(filePath);
      const source = readline.createInterface({ input, crlfDelay: Infinity });
      const lines = [];
      source.on('line', (line) => lines.push(line));
      source.on('close', () => lines.forEach((line, index) => callback(line, index === lines.length - 1)));
    }
  };
}

let number = 0;
lineReader.eachLine(file, (line, last) => {
  number += 1;
  console.log(`${number} --> ${line}`);
  if (last) {
    fs.unlinkSync(file);
    fs.rmdirSync(directory);
  }
});
1 --> Line 1
2 --> Line 2
3 --> Line 3
4 -->
5 --> Line 5

安装后,示例使用 line-reader;否则,包含的回退使用 Node.js 流和 readline,同时为此样本保留相同的回调值。空白的第四行作为空字符串到达,因此编号和箭头在没有行文本的情况下打印。last 值对于清理或其他文件结尾处理很有用。