Viết tệp trong Node.js


1646

Tôi đã cố gắng tìm cách ghi vào tệp khi sử dụng Node.js, nhưng không thành công. Làm thế nào tôi có thể làm điều đó?

Câu trả lời:


2465

Có rất nhiều chi tiết trong API hệ thống tệp . Cách phổ biến nhất là:

const fs = require('fs');

fs.writeFile("/tmp/test", "Hey there!", function(err) {
    if(err) {
        return console.log(err);
    }
    console.log("The file was saved!");
}); 

// Or
fs.writeFileSync('/tmp/test-sync', 'Hey there!');

26
Tôi đã kiểm tra tập lệnh này bằng Node và tôi đã thử thay đổi đường dẫn tệp thành "/ home /", nhưng tôi đã gặp lỗi sau: { [Error: EACCES, open '/home/test.txt'] errno: 3, code: 'EACCES', path: '/home/test.txt' } Làm cách nào tôi có thể sửa đổi tập lệnh này để nó hoạt động bên ngoài /tmp?
Anderson Green

130
Cũng lưu ý rằng bạn có thể sử dụng fs.writeFileSync (...) để thực hiện điều tương tự một cách đồng bộ.
David Erwin

7
Có thể nó hơi cũ, nhưng @AndersonGreen, bạn cần chạy nút là root hoặc chmod / home đúng cách để cho phép quyền R / W cho chủ sở hữu quy trình nút hiện tại (tên người dùng khó khăn) để bạn có thể viết tệp
Denys Vitali

39
Trên thực tế, @DenysVitali, vấn đề là jane không thể ghi bất kỳ tập tin nào vào /home/.... Nói chung thư mục đó là 755 root: wheel (hoặc bất cứ thứ gì). Nếu nút muốn ghi một tệp là jane, nó sẽ dễ dàng hơn để ghi vào /home/jane/test.txt. Thay đổi /homethành một cái gì đó dễ dãi hơn 755 là một sai lầm rất lớn.
vòng cung

7
@JaneAvriette Chà, vì anh ta muốn lưu tập tin vào /homethư mục nên tôi đề nghị chmod nó. Tôi biết nó có thể tạo ra một vấn đề bảo mật. Nhưng tốt, nếu người dùng muốn lưu ở đó, đó là giải pháp. Tái bút: Tôi đồng ý với những gì bạn nói (:
Denys Vitali

537

Hiện tại có ba cách để viết một tập tin:

  1. fs.write(fd, buffer, offset, length, position, callback)

    Bạn cần đợi cuộc gọi lại để đảm bảo rằng bộ đệm được ghi vào đĩa. Nó không được đệm.

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

    Tất cả dữ liệu phải được lưu trữ cùng một lúc; bạn không thể thực hiện viết tuần tự.

  3. fs.createWriteStream(path, [options])

    Tạo một WriteStream, thuận tiện vì bạn không cần phải chờ gọi lại. Nhưng một lần nữa, nó không được đệm.

A WriteStream, như tên gọi, là một luồng. Một luồng theo định nghĩa là một bộ đệm có chứa dữ liệu di chuyển theo một hướng (nguồn ► đích). Nhưng một luồng có thể ghi không nhất thiết là bộ đệm được đệm. Một luồng được đệm bộ đệm khi bạn viết nthời gian và tại thời điểm đó n+1, luồng sẽ gửi bộ đệm đến kernel (vì nó đầy và cần phải được xóa).

Nói cách khác: Bộ đệm Một bộ đệm là đối tượng. Có hay không nó được đệm bộ đệm là một thuộc tính của đối tượng đó.

Nếu bạn nhìn vào mã, các WriteStreamkế thừa từ một Streamđối tượng có thể ghi . Nếu bạn chú ý, bạn sẽ thấy cách họ tuôn ra nội dung; họ không có hệ thống đệm.

Nếu bạn viết một chuỗi, nó được chuyển đổi thành bộ đệm, sau đó được gửi đến lớp gốc và được ghi vào đĩa. Khi viết các chuỗi, chúng không lấp đầy bất kỳ bộ đệm nào. Vì vậy, nếu bạn làm:

write("a")
write("b")
write("c")

Bạn đang làm:

fs.write(new Buffer("a"))
fs.write(new Buffer("b"))
fs.write(new Buffer("c"))

Đó là ba cuộc gọi đến lớp I / O. Mặc dù bạn đang sử dụng bộ đệm của bộ dữ liệu, nhưng dữ liệu không được đệm. Luồng được đệm sẽ thực hiện : fs.write(new Buffer ("abc")), một cuộc gọi đến lớp I / O.

Đến bây giờ, trong Node.js v0.12 (phiên bản ổn định được công bố 02/06/2015) hiện hỗ trợ hai chức năng: cork()uncork(). Dường như các chức năng này cuối cùng sẽ cho phép bạn đệm / xóa các cuộc gọi ghi.

Ví dụ, trong Java có một số lớp cung cấp các luồng được đệm ( BufferedOutputStream, BufferedWriter...). Nếu bạn viết ba byte, các byte này sẽ được lưu trong bộ đệm (bộ nhớ) thay vì thực hiện cuộc gọi I / O chỉ với ba byte. Khi bộ đệm đầy, nội dung sẽ được xóa và lưu vào đĩa. Điều này cải thiện hiệu suất.

Tôi không khám phá bất cứ điều gì, chỉ cần nhớ cách truy cập đĩa nên được thực hiện.


5
+1 - giải thích hay. Đối với luồng ghi, điều quan trọng là phải đọc tài liệu một cách cẩn thận. Nếu trả về false hoặc đóng, điều quan trọng là gọi wr.once ('Drain', function () {}) hoặc tôi đã bỏ lỡ các dòng không bị cạn kiệt khi quá trình kết thúc.
bryanmac

4
bất kỳ cơ hội nào bạn có thể cung cấp một ví dụ về cách sử dụng cork()uncork()cho những người trong chúng ta muốn thử nút 0.11 trước khi phát hành?
professormeowingtons

Đến bây giờ, Node v0.12 vẫn ổn định.
Tháng Tám

Theo phân tích mã từ GitHub, fs.writeFile dường như là hàm phổ biến nhất trong số các hàm bạn đã đề cập. Dưới đây là các ví dụ trong thế giới thực để sử dụng fs.writeFile
drorw

Có thư viện chất lượng sản xuất về npmthực hiện viết đệm?
nponeccop

266

Tất nhiên bạn có thể làm cho nó cao cấp hơn một chút. Không chặn, ghi bit và miếng, không ghi toàn bộ tệp cùng một lúc:

var fs = require('fs');
var stream = fs.createWriteStream("my_file.txt");
stream.once('open', function(fd) {
  stream.write("My first row\n");
  stream.write("My second row\n");
  stream.end();
});

17
Biến 'fd' được truyền vào hàm gọi lại cho stream.once là gì?
Scott Tesler

1
@ScottDavidTesler mô tả tập tin để bạn có thể đóng luồng sau khi bạn đã thực hiện với nó.
Alexey Kamenskiy

3
Khi nào tôi đóng luồng? Tại sao điều này không chặn? Chỉ tò mò, tôi đang cố gắng ghi vào một tệp nhật ký.
MetaGuru

1
Tôi không chắc chắn khi dòng chảy. Tôi đoán là có khả năng tuôn dòng theo yêu cầu.
Fredrik Andersson

1
@JoLiss Bạn sẽ phải chờ nó.
Fredrik Andersson

61

Viết đồng bộ

fs.writeFileSync (tệp, dữ liệu [, tùy chọn])

fs = require('fs');

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

Viết không đồng bộ

fs.writeFile (tệp, dữ liệu [, tùy chọn], gọi lại)

fs = require('fs');

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

Ở đâu

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

Đáng đọc các tài liệu Hệ thống tệp chính thức (fs) .


53
var path = 'public/uploads/file.txt',
buffer = new Buffer("some content\n");

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');
        })
    });
});

2
điều này thể hiện cách viết một tệp bằng các thao tác fs cấp thấp hơn. ví dụ: bạn có thể đảm bảo khi tệp đã ghi xong vào đĩa và đã phát hành các mô tả tệp.
Sean Glover

Vì trong ví dụ này, phần bù nếu được đặt thành '0' (= tham số thứ ba của fs.write()) ví dụ này chỉ hoạt động nếu mọi thứ đủ ngắn để được viết trong một cuộc gọi ghi.
Manfred

31

Tôi thích Index của ./articles/file-system .

Nó làm việc cho tôi.

Xem thêm Làm cách nào để tôi viết tệp trong node.js? .

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');
});

Nội dung của hellowworld.txt:

Hello World!

Cập nhật:
Như trong nút Linux ghi trong thư mục hiện tại, có vẻ như trong một số người khác thì không, vì vậy tôi thêm nhận xét này chỉ trong trường hợp:
Sử dụng ROOT_APP_PATH = fs.realpathSync('.'); console.log(ROOT_APP_PATH);nút này để đến nơi tệp được ghi.


Nơi tìm tập tin helloworld.txt? Tôi không thể tìm thấy nó trong bất kỳ thư mục ... cảm ơn.
Kai Feng nhai

trong thư mục bạn chạy tập lệnh
Sérgio

Điều đó thật kỳ lạ ... Tôi không thể tìm thấy nó ở bất cứ đâu. Nó sẽ được ẩn? cảm ơn lần nữa ~
Kai Feng Chew

6
Tôi chỉ tìm thấy nó. Sử dụng ROOT_APP_PATH = fs.realpathSync ('.'); console.log ( ROOT_APP_PATH ); để có được nơi tôi viết tập tin. Cảm ơn.
Kai Feng nhai

@ Sérgio: chúng ta có cần đóng writefile không? Tôi đang gọi một quy trình khác và tôi nhận được một thông báo lỗi liên quan đến tập tin được bắt đầu sử dụng bởi một số quy trình khác.
Amir

24

Các câu trả lời được cung cấp là ngày và một cách mới hơn để làm điều này là:

const fsPromises = require('fs').promises
await fsPromises.writeFile('/path/to/file.txt', 'data to write')

xem tài liệu ở đây để biết thêm


1
(node:23759) ExperimentalWarning: The fs.promises API is experimental
jgraup

@jgraup: bạn có đang sử dụng phiên bản mới nhất của nút không?
TrevTheDev

Nútv10.15.0
jgraup

7
Chức năng kèm theo phải không đồng bộ hoặc điều này sẽ không hoạt động.
Zimano

1
@wintercount Điều đó khá ngọt ngào!
Zimano

19

Tôi biết câu hỏi được hỏi về "ghi" nhưng theo nghĩa chung hơn là "chắp thêm" có thể hữu ích trong một số trường hợp vì nó dễ sử dụng trong một vòng lặp để thêm văn bản vào tệp (cho dù tệp có tồn tại hay không). Sử dụng "\ n" nếu bạn muốn thêm dòng, ví dụ:

var fs = require('fs');
for (var i=0; i<10; i++){
    fs.appendFileSync("junk.csv", "Line:"+i+"\n");
}

Vì hiện đã có sẵn, tôi khuyên bạn nên sử dụng constthay vì var, ví dụ const fs = require('fs');, để tránh các tác dụng phụ không mong muốn, đặc biệt nếu bạn đang làm việc với cơ sở mã lớn hơn một chút.
Manfred

11

OK, nó khá đơn giản vì Node có chức năng tích hợp sẵn cho việc này, nó được gọi là fsviết tắt của Hệ thống tệp và về cơ bản, mô-đun Hệ thống tệp NodeJS ...

Vì vậy, trước tiên yêu cầu nó trong tệp server.js của bạn như thế này:

var fs = require('fs');

fscó một vài phương pháp để ghi vào tệp, nhưng cách ưa thích của tôi là sử dụng appendFile, cách này sẽ nối thêm nội dung vào tệp và nếu tệp không tồn tại, sẽ tạo một, mã có thể như sau:

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

3
trích dẫn duy nhất trong chuỗi nên được thoát.
Tamer

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

Ví dụ: đọc tệp và ghi vào tệp khác:

  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");
                            });
                        }
                });

Nơi bạn đang ghi dữ liệu vào "to.text" ??
Ravi Shanker Reddy

Câu trả lời này thêm gì vào nhiều câu trả lời đã có sẵn về writeFile?
Dan Dascalescu

9

Bạn có thể ghi vào một tệp bằng mô-đun fs (hệ thống tệp).

Đây là một ví dụ về cách bạn có thể làm điều đó:

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');
    }
  });
};

Bạn cũng có thể muốn thoát khỏi cấu trúc mã gọi lại bên trong gọi lại này bằng cách sử dụng Lời hứaasync/ awaitcâu lệnh. Điều này sẽ làm cho cấu trúc mã không đồng bộ phẳng hơn nhiều. Để làm điều đó, có thể sử dụng một hàm produc.promisify (bản gốc) tiện dụng. Nó cho phép chúng ta chuyển từ cuộc gọi lại sang lời hứa. Hãy xem ví dụ với các fschức năng dưới đây:

// 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);
}

1
Tại sao các đoạn mã này và không phải là các đoạn mã? Họ sẽ không bao giờ có thể chạy trong một trình duyệt nào.
Zimano

@Zimano Theo tôi hiểu thì câu hỏi liên quan đến nodejs nên không cần chạy trên trình duyệt.
Manfred

1
@Quản lý chính xác! Tôi nghĩ bạn đã hiểu sai những gì tôi đang cố nói; không có điểm nào trong việc có đoạn trích vì đó là nodejs!
Zimano

5

Ở đây chúng tôi sử dụng w + để đọc / ghi cả hai hành động và nếu không tìm thấy đường dẫn tệp, nó sẽ được tạo tự động.

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');
            })
        });
    }
});

Nội dung có nghĩa là những gì bạn phải ghi vào tệp và độ dài của nó, 'content.length'.


3

Dưới đây là ví dụ về cách đọc tệp csv từ cục bộ và ghi tệp csv vào cục bộ.

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()

1
Điều này giới thiệu tất cả các loại phức tạp (MongoClient, JSON, v.v.) không liên quan đến câu hỏi.
Dan Dascalescu

3

fs.createWriteStream(path[,options])

optionscũng có thể bao gồm một starttùy chọn cho phép ghi dữ liệu tại một số vị trí trước phần đầu của tệp. Sửa đổi một tập tin thay vì thay thế nó có thể yêu cầu một flagschế độ r+thay vì chế độ mặc định w. Mã hóa có thể là bất kỳ một trong những mã được chấp nhận bởi Bộ đệm .

Nếu autoCloseđược đặt thành true (hành vi mặc định) trên 'error'hoặc 'finish'bộ mô tả tệp sẽ tự động bị đóng. Nếu autoCloselà sai, thì bộ mô tả tệp sẽ không bị đóng, ngay cả khi có lỗi. Ứng dụng có trách nhiệm đóng ứng dụng và đảm bảo không có rò rỉ mô tả tệp.

Giống như ReadStream , nếu fdđược chỉ định, WriteStream sẽ bỏ qua pathđối số và sẽ sử dụng bộ mô tả tệp được chỉ định. Điều này có nghĩa là không có 'open'sự kiện sẽ được phát ra. fdnên chặn; fds không chặn nên được chuyển qua net.Socket .

Nếu optionslà một chuỗi, thì nó chỉ định mã hóa.

Sau khi đọc bài viết dài này. Bạn nên hiểu làm thế nào nó hoạt động. Vì vậy, đây là một ví dụ về createWriteStream().

/* 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');

createWriteStreamđã được đề cập trong nhiều câu trả lời trước khi câu trả lời này.
Dan Dascalescu

0

Bạn có thể sử dụng thư viện easy-file-manager

cài đặt đầu tiên từ npm npm install easy-file-manager

Mẫu để tải lên và xóa tệp

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);
});

2
This modules is created to save and remove files.. Không phải là một câu trả lời.
Xanh

-1

Bạn có thể viết vào một tệp bằng ví dụ mã sau:

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.');
      }
    });
  }
});

1
writeFileđã được đưa ra như một câu trả lời nhiều lần, nhiều năm trước. Câu trả lời này thêm gì?
Dan Dascalescu

Ngoài ra tại sao bạn mở tập tin? Không nên trả lời về việc viết tập tin?
Michal
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.