关于javascript:在node.js中写入文件

Writing files in Node.js

在使用node.js时,我一直试图找到一种写入文件的方法,但没有成功。我该怎么做?


文件系统API中有很多细节。最常见的方法是:

1
2
3
4
5
6
7
8
const fs = require('fs');
fs.writeFile("/tmp/test","Hey there!", function(err) {
    if(err) {
        return console.log(err);
    }

    console.log("The file was saved!");
});

  • 我已经使用node测试了这个脚本,并尝试将文件路径更改为"/home/",但出现了以下错误:{ [Error: EACCES, open '/home/test.txt'] errno: 3, code: 'EACCES', path: '/home/test.txt' } 如何修改这个脚本,以便它在/tmp之外工作?
  • 还要注意,您可以使用fs.writefilesync(…)同步完成相同的事情。
  • 可能有点旧,但是@andersongreen,您需要以root或chmod/home的形式正确运行节点,以允许R/W权限访问当前节点进程所有者(您的用户名很难),以便编写文件。
  • 实际上,@denysvitali,问题是Jane不能将任何文件写入/home/...中。通常,该目录是755根目录:wheel(或其他目录)。如果node想以jane的形式写入文件,那么就更容易写入/home/jane/test.txt。把/home改成比755更宽松的东西是一个巨大的错误。
  • @Janeavriette好吧,因为他想把文件保存在/home目录中,所以我建议chmod。我知道这会产生安全问题。但是,如果用户想保存,这就是解决方案。附言:我同意你所说的。
  • 我正试图对一个基于ASCII的文件执行此操作,而空字符正被插入到其他每个字符中。忠告?
  • 这似乎是写入文件?要附加到文件的版本是什么?
  • 完成后,您是否需要使用fs.close()
  • 至少在ecmascript 6中,fs.writeFile被否决。不知道换了什么。
  • 如何在当前目录上写入?
  • @m98 "./file.txt"将写入当前目录。
  • "请注意,在同一文件上多次使用fs.writeFile而不等待回调是不安全的。对于这种情况,强烈建议使用fs.createWriteStream
  • 或ES2015异步/等待方式:await promisify(fs.writeFile)("./test.md", markdownFile);
  • 在哪里粘贴此代码?


目前有三种方法可以写入文件:

  • fs.write(fd, buffer, offset, length, position, callback

    您需要等待回调,以确保将缓冲区写入磁盘。它没有缓冲。

  • fs.writeFile(filename, data, [encoding], callback)

    所有数据必须同时存储;不能执行顺序写入。

  • fs.createWriteStream(path, [options]

    创建一个WriteStream,这很方便,因为您不需要等待回调。但同样,它没有缓冲。

  • 顾名思义,WriteStream是一条小溪。按定义,流是"缓冲区",其中包含朝一个方向移动的数据(源代码?目的地)。但可写流不一定是"缓冲"的。当您写入n次时,流被"缓冲",在n+1次时,流将缓冲发送到内核(因为缓冲已满,需要刷新)。

    换句话说,"缓冲区"就是对象。它是否"缓冲"是该对象的属性。

    如果查看代码,WriteStream继承自可写的Stream对象。如果你注意,你会发现它们是如何刷新内容的;它们没有任何缓冲系统。

    如果您编写一个字符串,它将被转换为缓冲区,然后发送到本机层并写入磁盘。在编写字符串时,它们不会填满任何缓冲区。所以,如果你这样做:

    1
    2
    3
    write("a")
    write("b")
    write("c")

    你正在做:

    1
    2
    3
    fs.write(new Buffer("a"))
    fs.write(new Buffer("b"))
    fs.write(new Buffer("c"))

    这是对I/O层的三个调用。虽然您使用的是"缓冲区",但数据不会被缓冲。缓冲流可以做到:fs.write(new Buffer ("abc")),对I/O层进行一次调用。

    截至目前,在node.js v0.12(2015年6月2日发布的稳定版本)中,现在支持两种功能:cork()uncork()。似乎这些函数最终将允许您缓冲/刷新写调用。

    例如,在Java中,有一些类提供缓冲流(EDCOX1,12,13,EDCOX1,…,…)。如果写入三个字节,这些字节将存储在缓冲区(内存)中,而不是只对三个字节进行I/O调用。当缓冲区已满时,内容将被刷新并保存到磁盘。这提高了性能。

    我没有发现任何东西,只是记住如何进行磁盘访问。

    • +1-很好的解释。对于写入流,必须仔细阅读文档。如果返回false或closing,则对调用writer.once("drain",function())很重要,否则会错过进程结束时未排出的行。
    • 您是否有机会为我们中想要试用0.11版本前节点的人提供一个如何使用cork()uncork()的示例?
    • 到目前为止,节点v0.12是稳定的。
    • 根据对Github代码的分析,fs.writefile似乎是您提到的最流行的函数。下面是使用fs.writefile的实际示例


    你当然可以让它更高级一点。不阻塞,写入位和块,不立即写入整个文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var fs = require('fs');
    var stream = fs.createWriteStream("my_file.txt");
    stream.once('open', function(fd) {
      stream.write("My first row
    "
    );
      stream.write("My second row
    "
    );
      stream.end();
    });

    • 什么是传递到stream.once回调的"fd"变量?
    • @scottdavidtesler文件描述符,这样您就可以在处理完流之后关闭它。
    • 我什么时候关闭小溪?为什么这是非阻塞的?只是好奇,我试图写一个日志文件。
    • 当你完成了流.Wr.()时,你总是可以做一个流。我会把它添加到例子中。
    • 如果服务器在Stuto.Enter()被调用之前会失败吗?本质上,我可以用它来错误日志记录到特定文件吗?(是的,我知道您可以在运行节点应用程序时指定这一点,但是对于某些错误,我想将其存储在与所有其他日志记录不同的文件中)。
    • 我不知道河水是不是冲出来的。我的猜测是,有可能按需冲洗水流。
    • "open"事件是否异步发生?我是必须等待它,还是可以立即开始写入流中?
    • @Joliss你得等它。
    • 此示例将留给我一个空的"my_file.txt"和一个writestream对象的转储。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    var path = 'public/uploads/file.txt',
    buffer = new Buffer("some content
    "
    );

    fs.open(path, 'w', function(err, fd) {
        if (err) {
            throw 'error opening file: ' + err;
        }

        fs.write(fd, buffer, 0, buffer.length, null, function(err) {
            if (err) throw 'error writing file: ' + err;
            fs.close(fd, function() {
                console.log('file written');
            })
        });
    });

    • 这演示了如何使用较低级别的fs操作写入文件。例如,您可以保证文件何时完成写入磁盘并释放了文件描述符。


    同步写入

    fs.writeFileSync(file, data[, options])

    1
    2
    3
    fs = require('fs');

    fs.writeFileSync("synchronous.txt","synchronous write!")

    异步写入

    fs.writeFile(file, data[, options], callback)

    1
    2
    3
    4
    5
    6
    fs = require('fs');

    fs.writeFile('asynchronous.txt', 'asynchronous write!', (err) => {
      if (err) throw err;
      console.log('The file has been saved!');
    });

    在哪里?

    1
    2
    3
    4
    file <string> | <Buffer> | <URL> | <integer> filename or file descriptor
    data <string> | <Buffer> | <Uint8Array>
    options <Object> | <string>
    callback <Function>

    值得一读官方文件系统(FS)文档。


    我喜欢/文章/文件系统的索引。

    这对我很有用。

    另请参见如何在node.js中写入文件?.

    1
    2
    3
    4
    5
    6
    fs = require('fs');
    fs.writeFile('helloworld.txt', 'Hello World!', function (err) {
        if (err)
            return console.log(err);
        console.log('Wrote Hello World in file helloworld.txt, just check it');
    });

    helloworld.txt的内容:

    1
    Hello World!

    更新:就像在Linux节点中写入当前目录一样,在其他一些目录中似乎没有,所以我添加了这个注释以防万一:使用此ROOT_APP_PATH = fs.realpathSync('.'); console.log(ROOT_APP_PATH);获取文件的写入位置。

    • 在哪里可以找到文件helloworld.txt?我在任何文件夹中都找不到它…谢谢。
    • 在运行脚本的文件夹中
    • 真奇怪…我哪儿也找不到。它会被隐藏吗?再次感谢~
    • node test.js cat hello world.txt你好,世界!
    • 我刚找到它。使用这个根路径获取文件的写入位置。谢谢。
    • @S&233;rgio:是否需要关闭writefile?我正在调用另一个进程,并收到一个错误消息,说明文件已被其他进程使用。


    我知道关于"写"的问题,但在更一般的意义上,"附加"在某些情况下可能很有用,因为在循环中很容易将文本添加到文件中(无论文件是否存在)。如果要添加行,请使用"",例如:

    1
    2
    3
    4
    5
    var fs = require('fs');
    for (var i=0; i<10; i++){
        fs.appendFileSync("junk.csv","Line:"+i+"
    "
    );
    }

    • 应该是EDOCX1×1,对吧?
    • 修好了,谢谢0x48piraj
    • 只是需要这个!


    1
    2
    3
    4
    5
     var fs = require('fs');
     fs.writeFile(path +"\\message.txt","Hello", function(err){
     if (err) throw err;
      console.log("success");
    });

    例如:读取文件并写入另一个文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
      var fs = require('fs');
        var path = process.cwd();
        fs.readFile(path+"\\from.txt",function(err,data)
                    {
                        if(err)
                            console.log(err)
                        else
                            {
                                fs.writeFile(path+"\\to.text",function(erro){
                                    if(erro)
                                        console.log("error :"+erro);
                                    else
                                        console.log("success");
                                });
                            }
                    });

    • 在哪里将数据写入"to.text"??


    您可以使用fs(文件系统)模块写入文件。

    下面是一个示例,说明您可以如何执行此操作:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    const fs = require('fs');

    const writeToFile = (fileName, callback) => {
      fs.open(fileName, 'wx', (error, fileDescriptor) => {
        if (!error && fileDescriptor) {
          // Do something with the file here ...
          fs.writeFile(fileDescriptor, newData, (error) => {
            if (!error) {
              fs.close(fileDescriptor, (error) => {
                if (!error) {
                  callback(false);
                } else {
                  callback('Error closing the file');
                }
              });
            } else {
              callback('Error writing to new file');
            }
          });
        } else {
          callback('Could not create new file, it may already exists');
        }
      });
    };

    您可能还希望通过使用promises和async/await语句来消除回调代码结构中的回调。这将使异步代码结构更加简单。为此,可以使用一个方便的util.promisify(原始)函数。它允许我们从回拨转向承诺。请看下面使用fs函数的示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // Dependencies.
    const util = require('util');
    const fs = require('fs');

    // Promisify"error-back" functions.
    const fsOpen = util.promisify(fs.open);
    const fsWrite = util.promisify(fs.writeFile);
    const fsClose = util.promisify(fs.close);

    // Now we may create 'async' function with 'await's.
    async function doSomethingWithFile(fileName) {
      const fileDescriptor = await fsOpen(fileName, 'wx');
     
      // Do something with the file here...
     
      await fsWrite(fileDescriptor, newData);
      await fsClose(fileDescriptor);
    }


    在这里,我们使用w+来读/写两个操作,如果没有找到文件路径,它将自动创建。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    fs.open(path, 'w+', function(err, data) {
        if (err) {
            console.log("ERROR !!" + err);
        } else {
            fs.write(data, 'content', 0, 'content length', null, function(err) {
                if (err)
                    console.log("ERROR !!" + err);
                fs.close(data, function() {
                    console.log('written success');
                })
            });
        }
    });

    内容是指必须写入文件的内容及其长度"content.length"。


    这里是如何从本地读取文件CSV并将CSV文件写入本地的示例。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    var csvjson = require('csvjson'),
        fs = require('fs'),
        mongodb = require('mongodb'),
        MongoClient = mongodb.MongoClient,
        mongoDSN = 'mongodb://localhost:27017/test',
        collection;

    function uploadcsvModule(){
        var data = fs.readFileSync( '/home/limitless/Downloads/orders_sample.csv', { encoding : 'utf8'});
        var importOptions = {
            delimiter : ',', // optional
            quote     : '"' // optional
        },ExportOptions = {
            delimiter   :",",
            wrap        : false
        }
        var myobj = csvjson.toSchemaObject(data, importOptions)
        var exportArr = [], importArr = [];
        myobj.forEach(d=>{
            if(d.orderId==undefined || d.orderId=='') {
                exportArr.push(d)
            } else {
                importArr.push(d)
            }
        })
        var csv = csvjson.toCSV(exportArr, ExportOptions);
        MongoClient.connect(mongoDSN, function(error, db) {
            collection = db.collection("orders")
            collection.insertMany(importArr, function(err,result){
                fs.writeFile('/home/limitless/Downloads/orders_sample1.csv', csv, { encoding : 'utf8'});
                db.close();
            });            
        })
    }

    uploadcsvModule()


    OK,这很简单,因为节点有内置的功能,它被称为EDCOX1×2,它代表文件系统,基本上是NoDEJS文件系统模块…

    所以首先需要在你的Server .js文件中这样:

    1
    var fs = require('fs');

    fs有很少的方法来写文件,但我的首选方法是使用appendFile,这将把东西附加到文件中,如果文件不存在,将创建一个,代码如下:

    1
    2
    3
    4
    fs.appendFile('myFile.txt', 'Hi Ali!', function (err) {
      if (err) throw err;
      console.log('Thanks, It\'s saved to the file!');
    });

    • 字符串中的单引号应转义。


    您可以通过以下代码示例写入文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
      var data = [{'test': '123', 'test2': 'Lorem Ipsem '}];        
      fs.open(datapath + '/data/topplayers.json', 'wx', function(error, fileDescriptor){        
        if(!error && fileDescriptor){        
            var stringData = JSON.stringify(data);        
            fs.writeFile(fileDescriptor, stringData, function(error){        
                if(!error){        
                    fs.close(fileDescriptor, function(error){        
                        if(!error){        
                            callback(false);        
                        }else{        
                            callback('Error in close file');        
                        }        
                    });        
                }else{        
                    callback('Error in writing file.');        
                }        
            });        
        }        
    }

    fs.createWriteStream(path[,options])

    options may also include a start option to allow writing data at some position past the beginning of the file. Modifying a file rather than replacing it may require a flags mode of r+ rather than the default mode w. The encoding can be any one of those accepted by Buffer.

    If autoClose is set to true (default behavior) on 'error' or 'finish' the file descriptor will be closed automatically. If autoClose is false, then the file descriptor won't be closed, even if there's an error. It is the application's responsibility to close it and make sure there's no file descriptor leak.

    Like ReadStream, if fd is specified, WriteStream will ignore the path argument and will use the specified file descriptor. This means that no 'open' event will be emitted. fd should be blocking; non-blocking fds should be passed to net.Socket.

    If options is a string, then it specifies the encoding.

    之后,阅读这篇长篇文章。你应该理解它是如何工作的。这里有一个createWriteStream()的例子。

    1
    2
    3
    4
    /* The fs.createWriteStream() returns an (WritableStream {aka} internal.Writeable) and we want the encoding as 'utf'-8 */
    /* The WriteableStream has the method write() */
    fs.createWriteStream('out.txt', 'utf-8')
    .write('hello world');

    您可以使用库easy-file-manager

    首先从NPM安装npm install easy-file-manager

    上传和删除文件的示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var filemanager = require('easy-file-manager')
    var path ="/public"
    var filename ="test.jpg"
    var data; // buffered image

    filemanager.upload(path,filename,data,function(err){
        if (err) console.log(err);
    });

    filemanager.remove(path,"aa,filename,function(isSuccess){
        if (err) console.log(err);
    });

    • This modules is created to save and remove files.。不是答案。


    请尝试以下操作:

    1
    2
    3
    4
    5
    fs.readFile(`${__dirname}/fileName`, 'utf-8',(err, contents) => {
        if (err) throw Error(err){
            console.log(contents)
        }
    });