]> git.ardis.lu - csvio/commitdiff
Add example of processing `.csv.gz` files
authorArdis Lu <ardisglu@gmail.com>
Mon, 15 Sep 2025 03:22:11 +0000 (20:22 -0700)
committerArdis Lu <ardisglu@gmail.com>
Mon, 15 Sep 2025 03:22:11 +0000 (20:22 -0700)
examples/README.md
examples/data/ex1_9-in.csv.gz [new file with mode: 0644]
examples/data/ex1_9-out.csv.gz [new file with mode: 0644]
examples/ex1_9.js [new file with mode: 0644]
test/examples.test.js

index 607878ae5ced960e5f1144dba07d1b8be6a3d31b..4238659a0e100113c17427184d356bdf14bc9e45 100644 (file)
@@ -30,6 +30,8 @@ These examples demonstrate the most common, expected usage.
 
 [Example 1.8: Read from `stdin` and write to `stdout`](./ex1_8.js) ([input](./data/ex1_8-in.csv), [output](./data/ex1_8-out.csv))
 
+[Example 1.9: Read and write a `.csv.gz` file](./ex1_9.js) ([input](./data/ex1_9-in.csv.gz), [output](./data/ex1_9-out.csv.gz))
+
 ### Section 2: Error strategies
 
 These examples demonstrate using the `onError` option to handle transformations that may throw errors.
diff --git a/examples/data/ex1_9-in.csv.gz b/examples/data/ex1_9-in.csv.gz
new file mode 100644 (file)
index 0000000..70028c2
Binary files /dev/null and b/examples/data/ex1_9-in.csv.gz differ
diff --git a/examples/data/ex1_9-out.csv.gz b/examples/data/ex1_9-out.csv.gz
new file mode 100644 (file)
index 0000000..53ca670
Binary files /dev/null and b/examples/data/ex1_9-out.csv.gz differ
diff --git a/examples/ex1_9.js b/examples/ex1_9.js
new file mode 100644 (file)
index 0000000..e4c10a9
--- /dev/null
@@ -0,0 +1,33 @@
+// ## Example 1.9: Read and write a `.csv.gz` file
+// 
+// If your input or output files are not direct CSV files, you can create CSVReader and CSVWriter as
+// TransformStream instances by passing nothing to the constructors. This usage is convenient for
+// interoperating with other Web APIs, such as the Compression Streams API to read and write `.gz` files.
+// 
+// Note there is no need to save the CSVs to intermediate temporary working files, streams allow you to
+// directly process the `.gz` files.
+
+import { createWriteStream } from 'node:fs';
+import { Writable } from 'node:stream';
+
+import { CSVReader, CSVTransformer, CSVWriter } from '../src/index.js';
+
+import { createFileStream } from '../src/core.js';
+import { setGzipOSByteToUnknown } from '../test/utils.js';
+
+function timesTwo(row) {
+  return [Number(row[0]) * 2, Number(row[1]) * 2];
+}
+
+await createFileStream(new URL('./data/ex1_9-in.csv.gz', import.meta.url))
+  .pipeThrough(new DecompressionStream('gzip'))
+  .pipeThrough(new TextDecoderStream())
+  .pipeThrough(new CSVReader())
+  .pipeThrough(new CSVTransformer(timesTwo))
+  .pipeThrough(new CSVWriter()) // No need to use TextEncoderStream on this end, CompressionStream can handle text.
+  .pipeThrough(new CompressionStream('gzip'))
+  .pipeTo(Writable.toWeb(createWriteStream(new URL('./data/ex1_9-out.csv.gz', import.meta.url))));
+
+// Overriding platform-specific metadata on the `.gz` file so this test is consistent across platforms. This step is
+// NOT necessary to actually use the `.gz` file in normal situations.
+await setGzipOSByteToUnknown(new URL('./data/ex1_9-out.csv.gz', import.meta.url));
index 8e49070de30b150b13f75a3a2ca423c268ce0114..0476c3c95dcfa38ea7c34b3668f7a4f45eaa6def 100644 (file)
@@ -11,15 +11,19 @@ import { createTempFolder, assertConsole } from './utils.js';
 const dir = await createTempFolder();
 const tempExamples = pathToFileURL(`${dir}/examples/`); // Trailing forward slash is REQUIRED for using this URL as a URL base later
 const tempSrc = pathToFileURL(`${dir}/src/`);
+const tempTest = pathToFileURL(`${dir}/test/`);
 const actualExamples = new URL('../examples/', import.meta.url);
 const actualSrc = new URL('../src/', import.meta.url);
+const actualTest = new URL('../test/', import.meta.url);
 await Promise.all([
   mkdir(tempExamples, { recursive: true }),
-  mkdir(tempSrc, { recursive: true })
+  mkdir(tempSrc, { recursive: true }),
+  mkdir(tempTest, { recursive: true })
 ]);
 await Promise.all([
   cp(actualExamples, tempExamples, { recursive: true }),
-  cp(actualSrc, tempSrc, { recursive: true })
+  cp(actualSrc, tempSrc, { recursive: true }),
+  cp(actualTest, tempTest, { recursive: true })
 ]);
 
 const tests = [];
@@ -58,6 +62,15 @@ suite('examples', { concurrency: true }, () => {
         ok(actual.equals(expected));
       });
     }
+    else if (name === 'ex1_9') {
+      test(name, { concurrency: true }, async () => {
+        const output = new URL(`./data/${name}-out.csv.gz`, tempExamples);
+        const expected = await readFile(output);
+        await import(code);
+        const actual = await readFile(output);
+        ok(actual.equals(expected));
+      });
+    }
     else {
       test(name, { concurrency: true }, async () => {
         const expected = await readFile(output);
This page took 0.035731 seconds and 4 git commands to generate.