Получить данные из fs.readFile

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

Логи undefined, почему?

karaxuna
источник
1
fs.readFileSync также имеет интересные функции для чтения файла, даже если он в формате unicode utf8.
Praneeth
NB fs.readFile также может сделать это ... см. Мой ответ ниже
Доминик

Ответы:

348

Чтобы пояснить, что сказал @Raynos, определенная вами функция является асинхронным обратным вызовом. Он не выполняется сразу, а выполняется после завершения загрузки файла. Когда вы вызываете readFile, управление возвращается немедленно и выполняется следующая строка кода. Поэтому, когда вы вызываете console.log, ваш обратный вызов еще не был вызван, и этот контент еще не был установлен. Добро пожаловать в асинхронное программирование.

Пример подходов

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

Или, что еще лучше, как показывает пример Raynos, оберните ваш вызов в функцию и передайте свои собственные обратные вызовы. (Очевидно, это лучшая практика). Я думаю, что привычка оборачивать асинхронные вызовы в функцию, которая принимает обратный вызов, избавит вас от многих хлопот и грязного кода.

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

doSomething (function doSomethingAfter(err, result) {
    // process the async result
});
Мэтт Эш
источник
2
Синхронизация ввода / вывода имеет свое место - это хорошо, если вы делаете небольшую систему сборки или инструмент. На больших системах или серверных приложениях лучше избегать этого.
RobW
28
Не все это веб-сервер. И нет ничего ужасного в том, чтобы использовать синхронизированные версии методов для одноразовых вызовов до того, как сервер начнет принимать запросы. Любой, кто использует Node, должен понимать, почему, прежде чем его использовать. Определенно, прежде чем напрасно писать об этом.
Эрик Реппен
7
Вы должны включить 'utf8'после имени файла в качестве дополнительного параметра, иначе он просто вернет буфер. См .: stackoverflow.com/questions/9168737/…
DollarAkshay
252

На самом деле есть синхронная функция для этого:

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

Асинхронный

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

Асинхронно читает все содержимое файла. Пример:

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

Обратному вызову передаются два аргумента (err, data), где data - это содержимое файла.

Если кодировка не указана, возвращается необработанный буфер.


Синхронная

fs.readFileSync(filename, [encoding])

Синхронная версия fs.readFile. Возвращает содержимое файла с именем filename.

Если указано кодирование, то эта функция возвращает строку. В противном случае он возвращает буфер.

var text = fs.readFileSync('test.md','utf8')
console.log (text)
логан
источник
Быстрый вопрос, каково использование буфера, который возвращается в синхронной версии readFile? Если я читаю файл синхронно и не передаю кодировку, он печатает буфер, как я могу это использовать? Спасибо.
codingbbq
12
У меня был опыт с этим недавно. Скажем , наш буфер data. if (Buffer.isBuffer( data){ result = data.toString('utf8'); }Теперь мы преобразовали буфер в читаемый текст. Это хорошо для чтения открытого текста или проверки файла на соответствие форматам. Я мог бы сделать попытку / поймать, чтобы увидеть, если это, например, файл JSON; но только после того, как буфер преобразован в текст. Посмотрите здесь для получения дополнительной информации: nodejs.org/api/buffer.html
Логан
Также, насколько я знаю, буферы - это потоки октетов, и они хороши для отправки данных «по частям». Вы, наверное, видели, что буфер что-то вроде AF 42 F1. Очень практично для общения клиент-сервер-клиент.
Логан
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)
})
Raynos
источник
6
Большое спасибо, если бы у меня было 15 оценок, я бы проголосовал за ваш ответ :)
karaxuna
Привет, в первой строке вашего кода function readContent(callback), callbackзарезервированное слово? Я имею в виду, это стандартный способ реализации обратных вызовов для ваших пользовательских функций? Я только начал изучать узел.
Амаль Энтони
3
Привет Амаль. Обратный вызов - это просто аргумент, передаваемый его функции, это может быть eventили cлюбое другое имя, которое вам нравится - это не зарезервированное слово в Javascript, и я предполагаю, что то же самое распространяется на Node.js.
RealDeal_EE'18
readContent(function (err, content)выдает синтаксическую ошибку при использовании функции в качестве параметра.
Монсто
66

Использование обещаний с ES7

Асинхронное использование с mz / fs

mzМодуль обеспечивает promisified версии библиотеки ядра узла. Использовать их просто. Сначала установите библиотеку ...

npm install mz

Затем...

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

В качестве альтернативы вы можете написать их в асинхронных функциях:

async function myReadfile () {
  try {
    const file = await fs.readFile('./Index.html');
  }
  catch (err) { console.error( err ) }
};
Эван Кэрролл
источник
6
это будущее, и все должны высоко его поддержать :) спасибо
PirateApp
2
выглядит интересно. Одна опечатка: 'console.error (catch)' должна быть 'console.error (err)', я полагаю).
Philwalk
2
Если вы не хотите добавлять дополнительный пакет, попробуйте решение
@doctorlee
18
var data = fs.readFileSync('tmp/reltioconfig.json','utf8');

используйте это для синхронного вызова файла, без кодирования его вывода в виде буфера.

user2266928
источник
2
Вам нужна пустая строка перед блоками кода, чтобы хорошенькая печать
появилась
краткий и лучший!
Бриллиант
13

Эта линия будет работать,

const content = fs.readFileSync('./Index.html', 'utf8');
console.log(content);
Аравин
источник
1
Прошло 7 лет :) fs.readFileSyncЭто метод синхронизации, поэтому нет необходимости await. Await полезен с обещаниями ( nodejs.org/api/fs.html#fs_fs_promises_api ), когда вы хотите написать асинхронный код с синтаксисом, похожим на код синхронизации.
Караксуна
@ karaxuna, да. удален. Я только что столкнулся с этим делом сегодня, и я решил, используя приведенный выше код.
Аравин
1
Это самый простой ответ. Если вам не нужен асинхронный режим, зачем вообще смешивать асинхронную версию с обратными вызовами, асинхронным / ожидающим и т. Д.? Это путь.
Мастер Уток
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!");
      });
    });
  }
doctorlee
источник
5
Пожалуйста, не просто вставляйте код в свой ответ ... объясните, почему он отличается и как он решает проблему.
Студио,
@doctorlee Это на самом деле работает для меня, без какой-либо внешней библиотеки. Объяснение обязательно.
Ашутош Чамоли
7

Синхронизация и асинхронное чтение файла:

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

Чит-узел доступен в файле read_file .

Zeeshan Hassan Memon
источник
7

Как сказано, fs.readFileэто асинхронное действие. Это означает, что когда вы указываете узлу читать файл, вы должны учитывать, что это займет некоторое время, а тем временем узел продолжал выполнять следующий код. В вашем случае это: console.log(content);.

Это похоже на отправку какой-то части вашего кода в долгое путешествие (например, чтение большого файла).

Посмотрите на комментарии, которые я написал:

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

Вот почему contentвсе еще пусто, когда вы входите в систему. узел еще не получил содержимое файла.

Это может быть решено путем перемещения console.log(content)внутри функции обратного вызова, сразу после content = data;. Таким образом, вы увидите журнал, когда узел завершит чтение файла и после того, как contentполучит значение.

Таит-ЛМЗС
источник
6

Используйте встроенную библиотеку Promisify (Node 8+), чтобы сделать эти старые функции обратного вызова более элегантными.

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);
  }
}
Dominic
источник
Может быть в одной строке const doStuff = async (filePath) => fs.readFileSync(filePath, 'utf8');, не нужно использовать util.promisify wrap.
Rab
1
Доминик,
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);

Это просто потому, что узел асинхронный и он не будет ждать функцию чтения, и, как только программа запустится, он будет поддерживать значение как неопределенное, что на самом деле верно, потому что нет значения, назначенного переменной содержимого. Для обработки мы можем использовать обещания, генераторы и т. Д. Мы можем использовать обещание таким образом.

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

Следующая функция будет работать для asyncthen цепочек оберток или обещаний

const readFileAsync =  async (path) => fs.readFileSync(path, 'utf8');
Rab
источник
1

Вы можете прочитать файл по

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

Добавив, вы можете написать в файл,

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

и даже связать это вместе

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

Грубо говоря, вы имеете дело с node.js, который по своей природе асинхронный.

Когда мы говорим об асинхронности, мы говорим о выполнении или обработке информации или данных, когда имеем дело с чем-то другим. Это не синоним параллели, пожалуйста, напомните.

Ваш код:

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

В вашем примере он в основном выполняет сначала console.log, поэтому переменная 'content' не определена.

Если вы действительно хотите вывод, сделайте что-то вроде этого:

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

Это асинхронно. Будет трудно привыкнуть, но это то, что есть. Опять же, это грубое, но быстрое объяснение того, что такое асинхронность.

DayIsGreen
источник