【问题标题】:Node.js: difference in file size when copying csvNode.js:复制 csv 时文件大小的差异
【发布时间】:2020-07-13 22:18:06
【问题描述】:

我有以下代码,我从 CSV 读取并写入另一个 CSV。我将在写入另一个文件之前转换一些数据,但作为测试,我运行了代码,发现源文件和目标文件之间存在细微差异,而没有事件更改文件的任何内容。

  for(const m of metadata) {
      tempm = m;
      fname = path;
      const pipelineAsync = promisify(pipeline);
      if(m.path) {
        await pipelineAsync(
          fs.createReadStream(m.path),
          csv.parse({delimiter: '\t', columns: true}),
          csv.transform((input) => {
            return Object.assign({}, input);
          }),
          csv.stringify({header: true, delimiter: '\t'}),
          fs.createWriteStream(fname, {encoding: 'utf16le'})
        )
        let nstats = fs.statSync(fname);
        tempm['transformedPath'] = fname;
        tempm['transformed'] = true;
        tempm['t_size_bytes'] = nstats.size;
      }
  }

例如,我看到了,

file a: the source file size is `895631` while after copying destination file size is `898545`
file b: the source file size is `51388` while after copying destination file size is `52161`
file c: the source file size is `13666` while after copying destination file size is `13587`

但是当我不使用转换时,大小匹配,例如此代码在源和目标上产生完全相同的文件大小


  for(const m of metadata) {
      tempm = m;
      fname = path;
      const pipelineAsync = promisify(pipeline);
      if(m.path) {
        await pipelineAsync(
          fs.createReadStream(m.path),
          /*csv.parse({delimiter: '\t', columns: true}),
          csv.transform((input) => {
            return Object.assign({}, input);
          }),
          csv.stringify({header: true, delimiter: '\t'}),*/
          fs.createWriteStream(fname, {encoding: 'utf16le'})
        )
        let nstats = fs.statSync(fname);
        tempm['transformedPath'] = fname;
        tempm['transformed'] = true;
        tempm['t_size_bytes'] = nstats.size;
      }
  }

任何人都可以帮助确定我需要将哪些选项传递给 csv 转换,以便正确进行复制。

我正在做这个测试以确保我不会丢失大文件中的任何数据。

谢谢。

更新 1:我还检查了两个文件的编码是否相同。

更新 2:我注意到源文件有 CRLF 和目标文件有 LF。有没有办法我可以使用 node.js 保持不变,或者它是 OS 依赖的东西。

更新 3: 看起来问题是 EOL,我看到源文件有 CRLF,而目标文件/转换后的文件有 LF。我现在需要找到一种方法来指定我上面的代码,以便EOL 是一致的

【问题讨论】:

  • 尝试使用十六进制编辑器打开源文件和结果文件,然后检查差异。我认为这可能只是编码标头。
  • @Amadare42,感谢您的回复,我在十六进制编辑器中检查了文件,它们似乎有很大不同,尽管当我检查内容相同时。不知道哪里出了问题
  • 好吧,如果它们的内容相同,但在文件中有很多小的差异,几乎可以肯定只是编码差异。检查您是否可以在您选择的 csv 阅读框架中明确指定编码。
  • @Amadare42,我检查了编码是否相同,但仍然存在大小差异
  • “我在十六进制编辑器中检查了文件,它们似乎有很大不同” - 详细信息? “我已经检查过编码是否相同” - 你是怎么做到的?

标签: javascript node.js fs


【解决方案1】:

您需要设置 EOL 配置:

const { pipeline } = require('stream')
const { promisify } = require('util')
const fs = require('fs')
const csv = require('csv')
const os = require('os')


;(async function () {
  const pipelineAsync = promisify(pipeline)
  await pipelineAsync(
    fs.createReadStream('out'),
    csv.parse({ delimiter: ',', columns: true }),
    csv.transform((input) => {
      return Object.assign({}, input)
    }),
    // Here the trick:
    csv.stringify({ eol: true, record_delimiter: os.EOL, header: true, delimiter: '\t' }),
    fs.createWriteStream('out2', { encoding: 'utf16le' })
  )
})()

您也可以使用\r\n 或任何您需要的$-new-line\n

阅读source code可以发现此设置。

【讨论】:

    【解决方案2】:

    这种差异的两个主要来源是:

    1. EOL 样式(unix 或 ms-dos)
    2. 文件编码

    使用简单的 unix file 命令行实用程序,您可以检查源文件的编码和 EOL 样式。确保对 dest 文件使用相同的选项,任何差异都会消失。

    希望这会有所帮助。

    【讨论】:

    • 我如何检查 EOL 样式,你能分享一些我如何检查它的例子
    • 正如我所说的 @opensource-developer ,使用 unix file 命令行实用程序。只需发出命令$ file <filename>,您就会获得有关文件编码的详细信息,如果在输出中没有有关 EOL 的详细信息,则表示它是 unix 样式的 EOL 文件,如果显示类似 with CRLF line ending 的内容,则表示它是 ms -dos EOL 文件。
    • EOL 描述符是相同的,也是编码的,但我仍然看到大小不同
    • 所以@opensource-developer 你需要分享一些十六进制的sn-ps 与我们可以检查的差异。
    • npmjs.com/package/eol 可以帮助你@opensource-developer
    猜你喜欢
    • 2019-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-09
    • 2011-12-20
    • 2010-09-05
    • 1970-01-01
    • 2021-06-10
    相关资源
    最近更新 更多