node-csv icon indicating copy to clipboard operation
node-csv copied to clipboard

Missing header in output when input has only header

Open ksabr opened this issue 4 years ago • 9 comments

Hi there,

The following code

const inputFilePath = 'test_in.csv';
const outputCsv = fs.createWriteStream('test_out.csv');

fs.createReadStream(inputFilePath)
    .pipe(csv.parse({ columns: true }))
    .pipe(csv.stringify({ header: true, quoted: true }))
    .pipe(outputCsv);

Gives the output I expect (output same as input, apart from the quotes) when the input has lines beyond the header, but gives an empty file instead when test_in.csv only contains a header. Is that expected? How can I force it to always dump the header to the output?

Many thanks in advance.

ksabr avatar Apr 15 '21 14:04 ksabr

To make sure I understand, please provide a sample input, the actual output and the expected output.

wdavidw avatar Apr 15 '21 14:04 wdavidw

Hi @wdavidw ,

Thanks for the quick reply. The sample inputs are:

  • expected behaviour case test_in.csv:
Co1,Col2,Col3
1,2,3

(the corresponding output I get is

"Co1","Col2","Col3"
"1","2","3"
  • unexpected behaviour case test_in.csv:
Co1,Col2,Col3

output: empty file.

ksabr avatar Apr 15 '21 14:04 ksabr

ok, I get it. Don't know if we shall classify this as a bug, a missing feature, or even as a breaking change. This will have an impact on the visioning and potentially some angry users who might disagree. I tend to consider this as a bug.

wdavidw avatar Apr 15 '21 15:04 wdavidw

I believe that it ought to be treated as a bug based on this previous ticket (which I came across while researching this problem): https://github.com/adaltas/node-csv/issues/66

But having said that, if you have any suggestions for a quick fix, I would be most grateful :grinning: I would like to avoid having to count lines in the input files and decide what to do based on that.

ksabr avatar Apr 15 '21 15:04 ksabr

if a bug and a fix exist, even if it was years ago, I am surprised it is still there. Let me look at the code

wdavidw avatar Apr 15 '21 15:04 wdavidw

It seems like it is not a bug nor anything else, there is not much we can do about. The problem is not in the parser nor in the stringifier. You can see that it is implemented in the stringifier here.

You problem is that first, you parse the data with {column: true} and this return no records since there are none. Your solution is not to treat headers as such in parse, only when you stringify, eg:


fs.createReadStream(inputFilePath)
    .pipe(csv.parse())
    .pipe(csv.stringify({ header: true, quoted: true }))
    .pipe(outputCsv);

wdavidw avatar Apr 15 '21 15:04 wdavidw

When I try with that, I get

Error: Undiscoverable Columns: header option requires column option or object records
   at Stringifier._transform (/home/kerim/abtrace/GPAppTPP/node_modules/csv-stringify/lib/index.js:212:27)
    at Stringifier.Transform._read (_stream_transform.js:191:10)
    at Stringifier.Transform._write (_stream_transform.js:179:12)
    at doWrite (_stream_writable.js:403:12)
    at writeOrBuffer (_stream_writable.js:387:5)
    at Stringifier.Writable.write (_stream_writable.js:318:11)
    at Parser.ondata (_stream_readable.js:717:22)
    at Parser.emit (events.js:315:20)
    at addChunk (_stream_readable.js:295:12)
    at readableAddChunk (_stream_readable.js:271:9)

(for both input files, not just the header-only one)

ksabr avatar Apr 15 '21 15:04 ksabr

Do you really need headers, you could just

fs.createReadStream(inputFilePath)
    .pipe(csv.parse())
    .pipe(csv.stringify({ quoted: true }))
    .pipe(outputCsv);

Otherwise, you'll have to work around the stream API (or use the sync one), you can leverage transform to extract columns (https://csv.js.org/project/examples/#using-the-pipe-api) and re-inject it.

wdavidw avatar Apr 15 '21 17:04 wdavidw

Could we close the issue ?

wdavidw avatar Apr 26 '21 13:04 wdavidw