我如何在 Deno 中读取本地文件?

How do I read a local file in Deno?

我正在编写一个用 TypeScript 编写的字数统计程序,我正试图在 Deno 中 运行。我在调用它时没有参数,只是 deno ./word_count.ts,因此它应该具有默认的只读文件系统访问权限。我希望我可以使用 the standard browser fetch() API with the file: URL scheme 从文件系统中读取,如下所示:

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.

但是当我尝试时,我发现 fetch 不支持 file 网址:

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 (deno/js/main.ts:30:7)

如何在 Deno 中读取本地文件的内容?

Obsolete: This answer has been broken by the removal of the 'deno' module in favour of the Deno global in release v0.3.4.

Deno 在其标准库中包含一个 readFileSync(filename: string): Uint8Array 函数,可在特殊导入路径 'deno'.

中找到
import {readFileSync} from 'deno';

const bytes = readFileSync('./input.txt'); 

这会将文件的内容作为字节数组读取。如果文件包含您想要作为字符串的文本,如您的示例所示,您可以使用标准 ECMAScript TextDecoder class (MDN docs).

const utf8Decoder = new TextDecoder('utf-8');
const string = utf8Decoder.decode(bytes);

对于原始示例,这给了我们:

word_count.ts
import {readFileSync} from 'deno';

const countWords = (s: string): number =>
s.split(/\s+/g).filter(w => /[a-z0-9]/.test(w)).length;

const main = async () => {
    const decoder = new TextDecoder("utf-8");
    const bytes = readFileSync("./input.txt");
    const text = decoder.decode(bytes);
    const count = countWords(text);
    console.log(`I read ${count} words.`);
};

main();

产生所需的输出:

$ 德诺./word_count.ts
I read 9 words.

(更新: 不再需要 async function main() { ... } 中的包装代码,因为 Deno 现在支持 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.`);

查看文档: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.`);

请注意,您需要将数据显式解码为 UTF-8。

查看文档:https://deno.land/typedoc/index.html#readfile

使用阻塞读取

已接受的答案使用 readFileSync(),这是一个 阻塞 函数,因此不需要 main()async更新: 非阻塞也不再需要它 await)。一个简化的(有效的)示例是:

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.`);

注意这里没有await,所以代码稍微简单一些(更新:之前Deno支持顶层await区别在简单性更大)但是 Deno.readFileSync() 将阻塞线程直到文件被读取 - 对于像本例中那样执行一系列步骤的简单脚本,这很好,但如果它在服务器的请求处理程序中那么这对性能来说将是一场灾难。

使用较低级别 Deno.openDeno.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.`);

您可以将 main() 的前两行放在一行中:

const text = decoder.decode(await Deno.readAll(await Deno.open('input.txt')));

但它的可读性会降低。

查看文档:https://deno.land/typedoc/index.html#readall

甚至更低级别 Deno.openDeno.read

您甚至可以使用更低的杠杆 Deno.read,但您还必须分配缓冲区

查看文档:https://deno.land/typedoc/index.html#read

使用new File()抽象

还有一个 class 风格的文件读写抽象。

查看文档:https://deno.land/typedoc/classes/deno.file.html

std 0.62.0 / Deno 1.2.1 +

自从 std v0.62.0, readFileStr and readFileStrSync are removed 来自标准库。

Deno.readTextFile and Deno.readTextFileSync有相同的API,现在是要走的路。

writeFileStr / writeFileStrSync 相同)