I'm writing a word count program written in TypeScript that I'm trying to run in Deno. I'm invoking it with no arguments, just deno ./word_count.ts
, so it should have the default read-only filesystem access. I was hoping that I might be able to use the standard browser fetch()
API with the file:
URL scheme to read from the filesystem, like this:
word_count.ts
const countWords = (s: string): number => s.split(/\s+/g).filter(w => /[a-z0-9]/.test(w)).length; const main = async () => { const text = await (await fetch("file:///./input.txt")).text(); const count = countWords(text); console.log(`I read ${count} words.`); }; main();
input.txt
The quick brown fox jumps over the lazy dog.
But when I try I see I see that fetch
doesn't support file
URLs:
Error: an error occurred trying to connect: invalid URL, scheme must be http at FetchResponse.onMsg (deno/js/fetch.ts:121:21) at FetchRequest.onMsg (deno/js/fetch.ts:152:19) at onFetchRes (deno/js/fetch.ts:28:8) at onMessage$1 (deno/js/main.ts:30:7)
How can I read the contents of a local file in Deno?
Use the readFileSync() method to read a file's contents in TypeScript, e.g. readFileSync(join(__dirname, 'example. txt'), 'utf-8') . The method takes the path and encoding as parameters and returns the contents of the specified file.
To read a file, use FileReader , which enables you to read the content of a File object into memory. You can instruct FileReader to read a file as an array buffer, a data URL, or text.
Web browsers (and JavaScript) can only access local files with user permission. To standardize the file access from the browser, the W3C published the HTML5 File API in 2014. It defines how to access and upload local files with file objects in web applications.
Deno is a simple, modern, and secure runtime for JavaScript and TypeScript. It is an open source project created by Ryan Dahl, who developed Node. js.
(Update: wrapping code in async function main() { ... }
is no longer needed because Deno now supports top-level await
)
Deno.readTextFile
const countWords = (s: string): number => s.split(/\s+/g).filter(w => /[a-z0-9]/.test(w)).length; const text = await Deno.readTextFile('input.txt'); const count = countWords(text); console.log(`I read ${count} words.`);
See the docs at: https://doc.deno.land/builtin/stable#Deno.readTextFile
Deno.readFile
const countWords = (s: string): number => s.split(/\s+/g).filter(w => /[a-z0-9]/.test(w)).length; const decoder = new TextDecoder('utf-8'); const text = decoder.decode(await Deno.readFile('input.txt')); const count = countWords(text); console.log(`I read ${count} words.`);
Note that you need to explicitly decode the data as UTF-8.
See the docs at: https://deno.land/typedoc/index.html#readfile
The accepted answer uses readFileSync()
which is a blocking function so the main()
being async
is not needed (Update: it is no longer needed for non-blocking await
as well). A simplified (and working) example would be:
const countWords = (s: string): number => s.split(/\s+/g).filter(w => /[a-z0-9]/.test(w)).length; const decoder = new TextDecoder('utf-8'); const text = decoder.decode(Deno.readFileSync('input.txt')); const count = countWords(text); console.log(`I read ${count} words.`);
Note that there is no await
anywhere, so the code is slightly simpler (Update: before Deno supported top-level await
the difference in simplicity was bigger) but the Deno.readFileSync()
will block the thread until the file is read - for a simple script that does a sequence of steps like in this example this is fine, but if it was inside a request handler in a server then it would be a disaster for the performance.
Deno.open
and Deno.readAll
const countWords = (s: string): number => s.split(/\s+/g).filter(w => /[a-z0-9]/.test(w)).length; const decoder = new TextDecoder('utf-8'); const file = await Deno.open('input.txt'); const text = decoder.decode(await Deno.readAll(file)); const count = countWords(text); console.log(`I read ${count} words.`);
You could put the first two lines of main()
in a single line:
const text = decoder.decode(await Deno.readAll(await Deno.open('input.txt')));
but it would be less readable.
See the docs at: https://deno.land/typedoc/index.html#readall
Deno.open
and Deno.read
You could use even lower-lever Deno.read
but then you'd also have to allocate the buffers
See the docs at: https://deno.land/typedoc/index.html#read
new File()
abstractionThere is also a class-style abstraction for reading and writing files.
See the docs at: https://deno.land/typedoc/classes/deno.file.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With