如何在NodeJS中文件的特定位置覆盖?

问题描述

我的目标是替换NodeJS文件中特定位置的值,而不将文件的全部内容加载到RAM中(而不是fs.readFileSync(path,"utf8"))。它适用于非常大的文件({> 2^28 - 16个字节(允许的最大V8字符串长度))。

这是我的代码

const fs = require('fs');
const path = "./text.txt";
const cursor = 1;

(async () => {
        await new Promise((res,rej) => {
            const buffer = Buffer.from('ee');

            fs.open(path,'w+',function (err,fd) {

                if (err) {
                    console.log('Cant open file');
                    rej()
                } else {
                    fs.write(fd,buffer,buffer.length,cursor,writtenbytes) {
                        if (err) {
                            console.log('Cant write to file');
                            rej()
                        } else {
                            console.log(writtenbytes +
                                ' characters added to file');

                            res()
                        }
                    })
                }

            })
        })
})()

这是我启动程序之前"./text.txt"内容

foo

这是我启动程序后"./text.txt"内容

❓ee

和the的charCode等于0。

这是预期的结果:

fee

出什么事了?我该怎么解决

解决方法

问题是您在打开文件时使用w+作为模式。应该是r+

fs.open(path,'r+',function (err,fd) {
// −−−−−−−−−−−−^^

来自the documentation

'w+':打开文件进行读写。该文件已创建(如果不存在)或被截断(如果存在)

(我的重点)

因此,一旦它被截断,写到位置1就会在位置0上隐式地写0(或者在那儿留下不确定的垃圾,我不确定它指定了哪个)。

但使用r+

'r+':打开文件进行读写。如果文件不存在,则会发生异常。

...打开现有文件时不会被截断,然后可以写入特定位置。


对于它的价值,如果您使用的是async函数,则可能要使用fs API(fs.promises)的promises版本:

const fsp = require("fs").promises;

const path = "./text.txt";
const cursor = 1;

(async () => {
    const handle = await fsp.open(path,"r+");
    const buffer = Buffer.from('ee');
    console.log(buffer);
    try {
        const { bytesWritten } = await handle.write(buffer,buffer.length,cursor);
        console.log(`${bytesWritten} characters added to file`);
    } catch (err) {
        console.log(`Cant write to file: ${err.message || String(err)}`);
    } finally {
        handle.close();
    }
})()
.catch(err => {
    console.log(`Error: ${err.message || String(err)}`);
});

还请注意,您想捕获对顶级async函数可能抛出的诺言的拒绝。