Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I write files in Deno?

I was trying to write to a file using Deno.writeFile

await Deno.writeFile('./file.txt', 'some content')

But got the following cryptic error:

error: Uncaught TypeError: arr.subarray is not a function
    at Object.writeAll ($deno$/buffer.ts:212:35)
    at Object.writeFile ($deno$/write_file.ts:70:9)

What's the right way to write files in Deno?

like image 949
Marcos Casagrande Avatar asked May 26 '20 10:05

Marcos Casagrande


2 Answers

There are multiple ways to write a file in Deno, all of them require --allow-write flag and will throw if an error occurred, so you should handle errors correctly.

Using Deno.writeFile

This API takes a Uint8Array, not a string, the reason why you get that error. It also takes an optional WriteFileOptions object

const res = await fetch('http://example.com/image.png');
const imageBytes = new Uint8Array(await res.arrayBuffer());
await Deno.writeFile('./image.png', imageBytes);

There's also the synchronous API (it blocks the event loop as it does in Node.js).

Deno.writeFileSync('./image.png', imageBytes);

Writing strings


The easiest way is to use Deno.writeTextFile

await Deno.writeTextFile('./file.txt', 'some content');

You can also use Deno.writeFile with TextEncoder.

const encoder = new TextEncoder(); // to convert a string to Uint8Array
await Deno.writeFile('./file.txt', encoder.encode('some content'));

Streaming

Deno.open returns a FsFile which contains a WritableStream in .writable property, so you can just pipe a stream directly to it.

const res = await fetch('https://example.com/csv');
const file = await Deno.open('./some.csv', { create: true, write: true })

await res.body.pipeTo(file.writable);
file.close();

If you have a Reader instead of a ReadableStream you can convert it to a ReadableStream using readableStreamFromReader from std/streams:

import { readableStreamFromReader } from "https://deno.land/[email protected]/streams/mod.ts?s=readableStreamFromReader";

// ...

const readable = readableStreamFromReader(someReader);
await readable.pipeTo(file.writeable)

Low-level APIs

Using Deno.open and Deno.writeAll (or Deno.writeAllSync)

const file = await Deno.open('./image.png', { write: true, create: true });
/* ... */
await Deno.writeAll(file, imageBytes);
file.close(); // You need to close it!

See OpenOptions here. If you want to append you would do:

{ append: true }

And you can also use even lower-level APIs such as Deno.write or Writer.write

like image 132
Marcos Casagrande Avatar answered Nov 14 '22 17:11

Marcos Casagrande


You can use ensureDir to safely write files to possibly non-existent directories:

import { ensureDir } from "https://deno.land/[email protected]/fs/ensure_dir.ts";

ensureDir("./my/dir")
  .then(() => Deno.writeTextFile("./my/dir/file.txt", "some content"));

The containing file directory can be derived via dirname:

import { dirname } from "https://deno.land/[email protected]/path/mod.ts";

const file = "./my/dir/file.txt";
ensureDir(dirname(file)).then(() => Deno.writeTextFile(file, "some content"));

An alternative is ensureFile to assert file existence:

import { ensureFile } from "https:deno.land/std/fs/ensure_file.ts";

ensureFile(file).then(/* your file write method */)

This variant is slightly less verbose, with the cost of one additional write operation (file creation, if not exists).

like image 38
ford04 Avatar answered Nov 14 '22 16:11

ford04