Nhận dữ liệu từ fs.readFile


296
var content;
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    content = data;
});
console.log(content);

Nhật ký undefined, tại sao?


1
fs.readFileSync cũng có các tính năng thú vị để đọc tệp ngay cả khi nó ở định dạng unfode utf8.
Praneeth

NB fs.readFile cũng có thể làm điều đó ^ xem câu trả lời của tôi bên dưới
Dominic

Câu trả lời:


348

Để giải thích những gì @Raynos đã nói, chức năng bạn đã xác định là một cuộc gọi lại không đồng bộ. Nó không thực thi ngay lập tức, thay vào đó nó thực thi khi quá trình tải tập tin đã hoàn tất. Khi bạn gọi readFile, điều khiển được trả về ngay lập tức và dòng mã tiếp theo được thực thi. Vì vậy, khi bạn gọi console.log, cuộc gọi lại của bạn chưa được gọi và nội dung này chưa được đặt. Chào mừng bạn đến với lập trình không đồng bộ.

Cách tiếp cận ví dụ

const fs = require('fs');
// First I want to read the file
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    const content = data;

    // Invoke the next step here however you like
    console.log(content);   // Put all of the code here (not the best solution)
    processFile(content);   // Or put the next step in a function and invoke it
});

function processFile(content) {
    console.log(content);
}

Hoặc tốt hơn, như ví dụ Raynos cho thấy, bọc cuộc gọi của bạn trong một chức năng và chuyển qua các cuộc gọi lại của riêng bạn. (Rõ ràng đây là cách thực hành tốt hơn) Tôi nghĩ rằng thói quen gói các cuộc gọi không đồng bộ của bạn trong chức năng gọi lại sẽ giúp bạn tiết kiệm rất nhiều rắc rối và mã lộn xộn.

function doSomething (callback) {
    // any async callback invokes callback with response
}

doSomething (function doSomethingAfter(err, result) {
    // process the async result
});

2
Đồng bộ hóa I / O có vị trí của nó - thật tốt nếu bạn đang thực hiện một hệ thống hoặc công cụ xây dựng nhỏ. Trên các hệ thống lớn hơn hoặc ứng dụng máy chủ, cách tốt nhất là tránh nó.
RobW

27
Không phải tất cả mọi thứ là một máy chủ web. Và không có gì ghê gớm về việc sử dụng các phiên bản phương thức đồng bộ hóa cho các cuộc gọi một lần trước khi máy chủ bắt đầu nhận yêu cầu. Bất cứ ai sử dụng Node nên thực sự hiểu lý do tại sao trước khi sử dụng nó. Chắc chắn trước khi viết blog về nó.
Erik Reppen


7
Bạn phải đưa vào 'utf8'sau tên tệp dưới dạng tham số bổ sung, nếu không nó sẽ chỉ trả về bộ đệm. Xem: stackoverflow.com/questions/9168737/ từ
DollarAkshay

252

Thực sự có một chức năng đồng bộ cho việc này:

http://nodejs.org/api/fs.html#fs_fs_readfilesync_filename_encoding

Không đồng bộ

fs.readFile(filename, [encoding], [callback])

Đọc không đồng bộ toàn bộ nội dung của một tập tin. Thí dụ:

fs.readFile('/etc/passwd', function (err, data) {
  if (err) throw err;
  console.log(data);
});

Cuộc gọi lại được thông qua hai đối số (err, data), trong đó dữ liệu là nội dung của tệp.

Nếu không có mã hóa được chỉ định, thì bộ đệm thô được trả về.


Đồng bộ hóa

fs.readFileSync(filename, [encoding])

Phiên bản đồng bộ của fs.readFile. Trả về nội dung của tệp có tên tệp.

Nếu mã hóa được chỉ định thì hàm này trả về một chuỗi. Nếu không, nó trả về một bộ đệm.

var text = fs.readFileSync('test.md','utf8')
console.log (text)

Câu hỏi nhanh, việc sử dụng bộ đệm đang được trả về trong phiên bản đồng bộ của readFile là gì? Nếu tôi đọc một tệp đồng bộ và không vượt qua bất kỳ mã hóa nào, nó sẽ in bộ đệm, làm thế nào tôi có thể sử dụng tệp này? Cảm ơn bạn.
mã hóabbq

12
Tôi đã có kinh nghiệm với điều này gần đây. Hãy nói rằng bộ đệm của chúng tôi là data. if (Buffer.isBuffer( data){ result = data.toString('utf8'); }Bây giờ chúng tôi đã chuyển đổi bộ đệm thành văn bản có thể đọc được. Điều này tốt cho việc đọc tệp văn bản gốc hoặc kiểm tra tệp theo các loại định dạng. Tôi có thể thực hiện thử / bắt để xem đó có phải là tệp JSON không; nhưng chỉ sau khi bộ đệm được chuyển đổi thành văn bản. Xem tại đây để biết thêm thông tin: nodejs.org/api/buffer.html
Logan

Ngoài ra, theo như tôi biết, bộ đệm là các luồng octet và tốt cho việc gửi dữ liệu "từng mảnh một". Bạn phải đã thấy rằng bộ đệm là một cái gì đó như AF 42 F1. Rất thiết thực cho giao tiếp khách-máy chủ-khách hàng.
Logan

113
function readContent(callback) {
    fs.readFile("./Index.html", function (err, content) {
        if (err) return callback(err)
        callback(null, content)
    })
}

readContent(function (err, content) {
    console.log(content)
})

6
cảm ơn rất nhiều, nếu tôi có 15 điểm, tôi sẽ bỏ phiếu cho câu trả lời của bạn :)
karaxuna

Xin chào, trong dòng đầu tiên của mã của bạn function readContent(callback), là callbackmột từ dành riêng? Ý tôi là, đây có phải là cách tiêu chuẩn để thực hiện các cuộc gọi lại cho các chức năng tùy chỉnh của bạn? Tôi mới bắt đầu học nút.
Amal Antony

3
Chào Amal. Gọi lại đơn giản là đối số được truyền cho hàm của anh ta, nó có thể eventhoặc cbất kỳ tên nào bạn thích - đó không phải là một từ dành riêng trong Javascript và tôi sẽ giả sử như vậy kéo dài đến Node.js.
RealDeal_EE'18

readContent(function (err, content)cho tôi một lỗi cú pháp khi sử dụng hàm làm tham số.
monsto

66

Sử dụng lời hứa với ES7

Sử dụng không đồng bộ với mz / fs

Các mzmô-đun cung cấp các phiên bản promisified của thư viện nút lõi. Sử dụng chúng rất đơn giản. Đầu tiên cài đặt thư viện ...

npm install mz

Sau đó...

const fs = require('mz/fs');
fs.readFile('./Index.html').then(contents => console.log(contents))
  .catch(err => console.error(err));

Ngoài ra, bạn có thể viết chúng trong các hàm không đồng bộ:

async function myReadfile () {
  try {
    const file = await fs.readFile('./Index.html');
  }
  catch (err) { console.error( err ) }
};

6
đây là tương lai và sẽ được mọi người
ủng hộ

2
trông có vẻ thú vị. Một lỗi đánh máy: 'console.error (Catch)' nên là 'console.error (err)' Tôi đoán).
philwalk

2
Nếu bạn không muốn thêm gói bổ sung, hãy thử giải pháp của
@doctorlee

18
var data = fs.readFileSync('tmp/reltioconfig.json','utf8');

sử dụng điều này để gọi một tệp một cách đồng bộ, mà không mã hóa đầu ra hiển thị của nó dưới dạng bộ đệm.


2
Bạn cần một dòng trống trước các khối mã để in ấn đẹp.
royhowie

tóm tắt & tốt nhất!
Kim cương

12

Dòng này sẽ hoạt động,

const content = fs.readFileSync('./Index.html', 'utf8');
console.log(content);

1
7 năm trôi qua :) fs.readFileSynclà phương thức đồng bộ, nên không cần awaitở đó. Await rất hữu ích với các lời hứa ( nodejs.org/api/fs.html#fs_fs_promises_api ), khi bạn muốn viết mã async với cú pháp tương tự như mã đồng bộ hóa.
karaxuna

@karaxuna, vâng. loại bỏ. Tôi chỉ gặp trường hợp này ngày hôm nay và tôi đã giải quyết bằng cách sử dụng mã trên.
Aravin

1
Đây là câu trả lời đơn giản nhất. Nếu bạn không cần async, tại sao trên thế giới bạn sẽ kết hợp với phiên bản async, với các cuộc gọi lại, async / await, v.v?. Đây là con đường để đi.
Bậc thầy của vịt

8
const fs = require('fs')
function readDemo1(file1) {
    return new Promise(function (resolve, reject) {
        fs.readFile(file1, 'utf8', function (err, dataDemo1) {
            if (err)
                reject(err);
            else
                resolve(dataDemo1);
        });
    });
}
async function copyFile() {

    try {
        let dataDemo1 = await readDemo1('url')
        dataDemo1 += '\n' +  await readDemo1('url')

        await writeDemo2(dataDemo1)
        console.log(dataDemo1)
    } catch (error) {
        console.error(error);
    }
}
copyFile();

function writeDemo2(dataDemo1) {
    return new Promise(function(resolve, reject) {
      fs.writeFile('text.txt', dataDemo1, 'utf8', function(err) {
        if (err)
          reject(err);
        else
          resolve("Promise Success!");
      });
    });
  }

5
Xin đừng đặt mã vào câu trả lời của bạn ... giải thích tại sao nó khác và cách giải quyết vấn đề.
Studocwho

@doctorlee Điều này thực sự làm việc cho tôi, mà không cần bất kỳ thư viện bên ngoài. Giải thích là cần thiết cho chắc chắn.
Ashutosh Chamoli

7

cách đọc tệp đồng bộ và không đồng bộ:

//fs module to read file in sync and async way

var fs = require('fs'),
    filePath = './sample_files/sample_css.css';

// this for async way
/*fs.readFile(filePath, 'utf8', function (err, data) {
    if (err) throw err;
    console.log(data);
});*/

//this is sync way
var css = fs.readFileSync(filePath, 'utf8');
console.log(css);

Node Cheat Có sẵn tại read_file .


7

Như đã nói, fs.readFilelà một hành động không đồng bộ. Điều đó có nghĩa là khi bạn yêu cầu nút đọc một tệp, bạn cần xem xét rằng sẽ mất một thời gian và trong thời gian đó, nút tiếp tục chạy mã sau đây. Trong trường hợp của bạn, đó là:console.log(content); .

Nó giống như gửi một phần mã của bạn cho một chuyến đi dài (như đọc một tệp lớn).

Hãy xem các ý kiến ​​mà tôi đã viết:

var content;

// node, go fetch this file. when you come back, please run this "read" callback function
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    content = data;
});

// in the meantime, please continue and run this console.log
console.log(content);

Đó là lý do tại sao contentvẫn trống khi bạn đăng nhập nó. nút chưa lấy nội dung của tập tin.

Điều này có thể được giải quyết bằng cách di chuyển console.log(content)bên trong chức năng gọi lại, ngay sau đó content = data;. Bằng cách này, bạn sẽ thấy nhật ký khi nút đọc xong tệp và sau khi contentnhận được giá trị.


6

Sử dụng thư viện được tích hợp sẵn (Node 8+) để làm cho các hàm gọi lại cũ này trở nên thanh lịch hơn.

const fs = require('fs');
const util = require('util');

const readFile = util.promisify(fs.readFile);

async function doStuff() {
  try {
    const content = await readFile(filePath, 'utf8');
    console.log(content);
  } catch (e) {
    console.error(e);
  }
}

Có thể ở một dòng duy nhất const doStuff = async (filePath) => fs.readFileSync(filePath, 'utf8');, không cần bọc produc.promisify.
rab

1
Không sử dụng phiên bản đồng bộ hóa là điểm chính của vấn đề này và bạn nên xử lý các lỗi khi gọi nó
Dominic

4
var fs = require('fs');
var path = (process.cwd()+"\\text.txt");

fs.readFile(path , function(err,data)
{
    if(err)
        console.log(err)
    else
        console.log(data.toString());
});

2
var content;
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    content = data;
});
console.log(content);

Điều này chỉ là do nút không đồng bộ và nó sẽ không chờ chức năng đọc và ngay khi chương trình khởi động, nó sẽ điều khiển giá trị là không xác định, điều này thực sự đúng vì không có giá trị nào được gán cho biến nội dung. Để xử lý chúng ta có thể sử dụng lời hứa, máy phát điện, v.v. Chúng ta có thể sử dụng lời hứa theo cách này.

new Promise((resolve,reject)=>{
    fs.readFile('./index.html','utf-8',(err, data)=>{
        if (err) {
            reject(err); // in the case of error, control flow goes to the catch block with the error occured.
        }
        else{
            resolve(data);  // in the case of success, control flow goes to the then block with the content of the file.
        }
    });
})
.then((data)=>{
    console.log(data); // use your content of the file here (in this then).    
})
.catch((err)=>{
    throw err; //  handle error here.
})

2

Sau đây là chức năng sẽ hoạt động cho chuỗi asynchoặc thenchuỗi hứa

const readFileAsync =  async (path) => fs.readFileSync(path, 'utf8');

1

bạn có thể đọc tập tin bằng cách

var readMyFile = function(path, cb) {
      fs.readFile(path, 'utf8', function(err, content) {
        if (err) return cb(err, null);
        cb(null, content);
      });
    };

Thêm vào bạn có thể viết vào tập tin,

var createMyFile = (path, data, cb) => {
  fs.writeFile(path, data, function(err) {
    if (err) return console.error(err);
    cb();
  });
};

và thậm chí xâu chuỗi nó lại với nhau

var readFileAndConvertToSentence = function(path, callback) {
  readMyFile(path, function(err, content) {
    if (err) {
      callback(err, null);
    } else {
      var sentence = content.split('\n').join(' ');
      callback(null, sentence);
    }
  });
};

1

Nói một cách đại khái, bạn đang xử lý với node.js về bản chất không đồng bộ.

Khi chúng tôi nói về async, chúng tôi đang nói về việc thực hiện hoặc xử lý thông tin hoặc dữ liệu trong khi xử lý một cái gì đó khác. Nó không đồng nghĩa với song song, xin được nhắc nhở.

Ma cua ban:

var content;
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    content = data;
});
console.log(content);

Với mẫu của bạn, về cơ bản nó sẽ thực hiện phần console.log trước, do đó biến 'nội dung' không được xác định.

Nếu bạn thực sự muốn đầu ra, thay vào đó hãy làm một cái gì đó như thế này:

var content;
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    content = data;
    console.log(content);
});

Điều này là không đồng bộ. Sẽ khó để làm quen nhưng, nó là như vậy. Một lần nữa, đây là một lời giải thích sơ bộ nhưng nhanh chóng về sự không đồng bộ là gì.

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.