在 Node.js 中使用 WriteStream 和替换文件写入时出现问题

Issue when writing with WriteStream and replace-in-file in Node.js

我希望能够在运行时写入文件,同时还能够 replace/delete 文件中的某些行。 对于写作,我使用的是 fs.WriteStream 而对于替换,我使用的是 replace-in-file 库。 我写了很多次所以我不能使用fs.writeFile

我尝试在文件中写入几行,替换一些文本,然后添加新行。替换后,流的指针似乎不再指向文件末尾。

import * as fs from "fs";
const stream = fs.createWriteStream("./file.txt");
const replace = require("replace-in-file");
const option = {
    files: "./file.txt",
    from: /Second/,
    to: "After the first"
};

stream.write("First line \n");
stream.write("Second line \n");
stream.write("Third line \n");

replace(option)
    .then(results => {
        console.log("Replacement results:", results);
        stream.write("X");
    })
    .catch(error => {
        console.error("Error occurred:", error);
    });    

我希望文件包含以下文本: First line After the first line Third line X 不幸的是它包含: First line The after the first line XThird line

我无法解决我遇到的问题,但我能够在运行时相对更新文件。我创建了一个 File class ,它将文件的数据存储在一个字符串中。然后,我只在对文件进行重要更改时才写入文件。

有一些未包含但使用 fs 创建起来相当简单的 Util 函数。

class

export {};
import * as Util from "../Utility/Util";

export class File {
    /** A class to represent a file. Data isn't saved until you close/flush the file */
    private text: string; // Represents the text the file contains
    private path: string; // The path of the file
    private isOpen: boolean; // True when the file is open; False otherwise

    constructor(path: string) {
        this.path = path;
        this.text = "";
        this.isOpen = false;
    }

    open(): void {
        /**Must run before writing to file */

        if (this.isOpen) return; // Make sure file isn't opened twice
        Util.Log(`Opening file: ${this.path}`, 4);
        // Create the file if it doesn't already exist
        if (!Util.PathExists(this.path)) {
            Util.CreateFile(this.path);
        }

        this.isOpen = true;
        this.text = Util.ReadFile(this.path);
    }

    append(data: string): void {
        /** Adds data to the file */

        try {
            this.text += data;
        } catch (err) {
            const e: Error = err;
            if (e.name === "RangeError") {
                const errArr: string[] = [
                    "Error: RangeError",
                    "While writing data to files, the File class uses a string to save the data. That data is too big.",
                    "This happens every time you will try to write to much data to a file.",
                    "You must make the csv log files smaller."
                ];
                Util.SHUT_DOWN(errArr.join("\n"), e);
            }
        }
    }

    replace(oldData: string, newData: string): void {
        /** Replace the first occurrence oldData with newData */
        this.text = this.text.replace(new RegExp(oldData, ""), newData);
    }

    isEmpty(): boolean {
        /** Returns true if the file is completely empty */
        return this.text == "";
    }

    getLineWith(text: string): string {
        /** Returns the first line with the text in it */
        let lines = this.getLines();
        for (let i = 0; i < lines.length; i++) {
            if (lines[i].includes(text)) {
                return lines[i];
            }
        }

        return "";
    }

    deleteLineWith(data: string[]): void {
        /** Deletes the first line in the file that contains all of the strings in the array */
        let lines = this.getLines(); // Get all lines in the
        for (let i = 0; i < lines.length; i++) {
            let allDataFound = true;
            for (let g = 0; g < data.length; g++) {
                allDataFound = allDataFound && lines[i].includes(data[g]);
            }
            if (allDataFound) {
                const newLines = lines
                    .slice(0, i)
                    .concat(lines.slice(i + 1, lines.length));
                this.setTextByLines(newLines);
                // this.text = newLines.join("\n");
            }
        }
    }

    getLines(): string[] {
        /** Returns an array of the lines in the file */
        return this.text.split("\n");
    }

    setTextByLines(lines: string[]) {
        /** Sets the file's text given an array of lines */
        this.text = lines.join("\n");
    }

    close() {
        /** Close the file. Must run this to save changes */
        if (!this.isOpen) return; // Prevent multiple closings

        Util.Log(`Closing file: ${this.path}`, 3);
        this.flush();
        this.isOpen = false;
    }

    flush() {
        /** Writes to the file the text it supposed to have at the moment*/
        if (!this.isOpen) {
            return;
        }

        Util.WriteToFile(this.path, this.text);
    }

    getPath(): string {
        /** Get the path of the file */
        return this.path;
    }
}

用法:

import {File} from './FileHandler'
let f = new File('./newFile.txt')
f.open()  // File contains 0 lines
f.append('First line\n')  // File contains 0 lines
f.append('Second line\n')  // File contains 0 lines
f.flush()   // File contains 2 lines
f.append('Third line\n')  // File contains 2 lines
f.append('Fourth line\n')  // File contains 2 lines
f.close()  // File contains 4 lines

// Note: If the file had already X lines they would not be deleted.