Basic Unix paste可以用类似于Python的语言实现(该示例仅适用于两个文件;Unix Paste适用于多个文件):

def paste(fn1, fn2):
  with open(fn1) as f1:
    with open(fn2) as f2:
      for l1 in f1:
        l2 = f2.readline()
        if l2 != None:
          print(l1[:-1] + "\t" + l2[:-1])
        else:
          print(l1[:-1])
      for l2 in f2:
        print("\t" + l2[:-1])

import sys
if __name__ == "__main__":
  if len(sys.argv) >= 3:
    paste(sys.argv[1], sys.argv[2])

任务是在Node.js中实现相同的功能.Importantly,因为输入文件可能很大,所以实现应该逐行读取输入文件,而不是将整个文件读入内存.我想看看如何在没有外部包的情况下使用内置的Node功能来实现这一点.

请注意,使用同步I/O实现Unix Paste很容易,如Python示例所示,但Node不为行读取提供同步I/O.同时,有ways个异步I/O逐行读取一个文件,但联合读取两个文件比较困难,因为两个流不同步.

到目前为止,我能想到的唯一解决方案是使用基本的readAPI实现同步行读取.戴夫·牛顿在 comments 中指出,NPM n-readlines packageread多行代码中实现了这种方法.因为n-READLINS判断每个字节以查找行结束,我怀疑它效率不高,因此执行了microbenchmark,结果如下表所示.对于行读取(不适用于此任务),n读取行的速度是Node Readline实现的3倍,并且比在Python、Perl或Mawk中内置的行读取慢一个数量级.

如何正确实现Unix粘贴?N-readlines使用同步API.一个好的解决方案会更干净、更快吗?

Language Runtime Version Elapsed (s) User (s) Sys (s) Code
JavaScript node 21.5.0 6.30 5.33 0.90 lc-node.js
node 21.5.0 22.34 20.41 2.24 lc-n-readlines.js
bun 1.0.20 4.91 5.30 1.47 lc-node.js
bun 1.0.20 21.16 19.22 3.37 lc-n-readlines.js
k8 1.0 1.49 1.06 0.37 lc-k8.js
C clang 15.0.0 0.71 0.35 0.35 lc-c.c
python python 3.11.17 3.48 2.85 0.62 lc-python.py
perl perl 5.34.3 1.70 1.13 0.57 lc-perl.pl
awk mawk 1.3.4 2.08 1.27 0.80 lc-awk.awk
apple awk ? 90.06 87.90 1.12 lc-awk.awk

推荐答案

import { open as fsOpenAsync } from 'node:fs/promises'
import { createWriteStream } from 'node:fs'

const filenames = ['a.txt', 'b.txt', 'c.txt']
const outname = 'out.txt'

await paste(filenames, outname)

/**
 * Read multiple files line by line and write lines concatenated by `\t`
 */
async function paste(from: string[], to: string) {
  const files = await Promise.all(filenames.map(fn => fsOpenAsync(fn)))
  const zip = zipAsyncs(files.map(f => f.readLines()[Symbol.asyncIterator]()))
  const writeStream = createWriteStream(to, { flags: 'w' })
  for await (const lines of zip)
    writeStream.write(`${lines.map(e => e ?? '').join('\t')}\n`)
  writeStream.close()
  await Promise.all(files.map(f => f.close()))
}

/**
 * Zip multiple async iterables, returning `undefined` for missing values
 * @template {T}
 * @param {AsyncIterator<T>[]} its
 * @returns {AsyncGenerator<IteratorResult<T | undefined, any>[]>}
 */
async function* zipAsyncs(its) {
  while (true) {
    const results = await Promise.all(its.map(e => e.next()))
    yield results.map(r => r.value)
    if (results.every(r => r.done))
      return
  }
}

Javascript相关问答推荐

格式值未保存在redux持久切片中

无法在nextjs应用程序中通过id从mongoDB删除'

当试图显示小部件时,使用者会出现JavaScript错误.

简单的PayPal按钮集成导致404错误

如何在输入元素中附加一个属性为checkbox?

ChartJs未呈现

try 使用javascript隐藏下拉 Select

在Reaction中的handleSubmit按钮内,useSelector值仍然为空

NG/Express API路由处理程序停止工作

同一类的所有div';S的模式窗口

Nextjs 13.4 Next-Auth 4.2登录(&Quot;凭据&,{});不工作

删除加载页面时不存在的元素(JavaScript)

使用类型:assets资源 /资源&时,webpack的配置对象&无效

使用RxJS from Event和@ViewChild vs KeyUp事件和RxJS主题更改输入字段值

JavaScript -复制到剪贴板在Windows计算机上无效

P5.js中矩形内的圆弧

是否设置以JavaScript为背景的画布元素?

使用Library chart.js在一个带有两个y轴的图表中绘制两个数据集

不允许在对象文本中注释掉的属性

带元素数组的Mongo聚合