Uzyskaj dane z fs.readFile

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

Dzienniki undefined, dlaczego?

karaxuna
źródło
1
fs.readFileSync ma również fajne funkcje do odczytu pliku, nawet jeśli jest on w formacie Unicode utf8.
Praneeth
NB fs.readFile też może to zrobić ^ patrz moja odpowiedź poniżej
Dominic

Odpowiedzi:

347

Aby rozwinąć to, co powiedział @Raynos, zdefiniowana funkcja to asynchroniczne wywołanie zwrotne. Nie uruchamia się od razu, raczej wykonuje się po zakończeniu ładowania pliku. Po wywołaniu readFile kontrola jest natychmiast zwracana i wykonywany jest następny wiersz kodu. Kiedy więc wywołujesz plik console.log, Twoje wywołanie zwrotne nie zostało jeszcze wywołane, a ta treść nie została jeszcze ustawiona. Witamy w programowaniu asynchronicznym.

Przykładowe podejścia

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

Albo jeszcze lepiej, jak pokazuje przykład Raynos, zawiń swoje wywołanie w funkcji i przekaż własne wywołania zwrotne. (Najwyraźniej jest to lepsza praktyka). Myślę, że nabycie nawyku owijania wywołań asynchronicznych funkcją, która odbiera połączenia, pozwoli zaoszczędzić wiele problemów i niepotrzebnego kodu.

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

doSomething (function doSomethingAfter(err, result) {
    // process the async result
});
Matt Esch
źródło
2
Synchronizacja We / Wy ma swoje miejsce - jest w porządku, jeśli robisz mały system lub narzędzie. W większych systemach lub aplikacjach serwerowych najlepszą praktyką jest unikanie tego.
RobW
27
Nie wszystko jest serwerem WWW. I nie ma nic okropnego w okropnym używaniu wersji synchronizowanych metod dla połączeń jednorazowych, zanim serwer zacznie przyjmować żądania. Każdy, kto używa Węzła, powinien naprawdę zrozumieć, dlaczego go używa. Zdecydowanie przed rant-blogowaniem na ten temat.
Erik Reppen
7
Musisz podać 'utf8'po nazwie pliku jako dodatkowy parametr, w przeciwnym razie po prostu zwróci bufor. Zobacz: stackoverflow.com/questions/9168737/…
DollarAkshay
252

Istnieje w tym celu funkcja synchroniczna:

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

Asynchroniczny

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

Asynchronicznie odczytuje całą zawartość pliku. Przykład:

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

Do wywołania zwrotnego przekazywane są dwa argumenty (err, data), gdzie dane są zawartością pliku.

Jeśli nie określono kodowania, zwracany jest bufor surowy.


SYNCHRONICZNY

fs.readFileSync(filename, [encoding])

Synchroniczna wersja fs.readFile. Zwraca zawartość pliku o nazwie nazwa_pliku.

Jeśli określono kodowanie, funkcja ta zwraca ciąg znaków. W przeciwnym razie zwraca bufor.

var text = fs.readFileSync('test.md','utf8')
console.log (text)
Logan
źródło
Szybkie pytanie, jaki jest pożytek z bufora zwracanego w synchronicznej wersji readFile? Jeśli czytam plik synchronicznie i nie przekazuję żadnego kodowania, drukuje bufor, jak mogę tego użyć? Dziękuję Ci.
codingbbq
12
Miałem z tym ostatnio doświadczenie. Powiedzmy, że nasz bufor to data. if (Buffer.isBuffer( data){ result = data.toString('utf8'); }Teraz przekonwertowaliśmy bufor na czytelny tekst. Jest to dobre do odczytu pliku zwykłego tekstu lub testowania pliku pod kątem typów formatów. Mógłbym spróbować / złapać, aby zobaczyć, czy jest to na przykład plik JSON; ale dopiero po przekonwertowaniu bufora na tekst. Zajrzyj tutaj, aby uzyskać więcej informacji: nodejs.org/api/buffer.html
Logan
O ile wiem, bufory są strumieniami oktetów i nadają się do przesyłania danych „kawałek po kawałku”. Pewnie widziałeś, że bufor jest podobny AF 42 F1. Bardzo praktyczne do komunikacji klient-serwer-klient.
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)
})
Raynos
źródło
6
dziękuję bardzo, gdybym miał 15 marek, głosowałbym na twoją odpowiedź :)
karaxuna,
Cześć, czy w pierwszym wierszu kodu function readContent(callback)jest callbacksłowo zastrzeżone? Mam na myśli, czy to standardowy sposób na implementację wywołań zwrotnych dla niestandardowych funkcji? Właśnie zacząłem uczyć się węzła.
Amal Antony
3
Cześć Amal. Callback jest po prostu argument przekazany do swej funkcji, może to być eventalbo club dowolną nazwę - to nie jest słowo zarezerwowane w JavaScript, a ja zakładam samo rozciąga się Node.js.
RealDeal_EE'18,
readContent(function (err, content)daje mi błąd składniowy podczas używania funkcji jako parametru.
monsto
66

Korzystanie z obietnic w ES7

Wykorzystanie asynchroniczne z mz / fs

mzModuł zapewnia promisified wersje biblioteki węzła lokalnego. Korzystanie z nich jest proste. Najpierw zainstaluj bibliotekę ...

npm install mz

Następnie...

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

Możesz też napisać je w funkcjach asynchronicznych:

async function myReadfile () {
  try {
    const file = await fs.readFile('./Index.html');
  }
  catch (err) { console.error( err ) }
};
Evan Carroll
źródło
6
to jest przyszłość i wszyscy powinni być wysoko oceniani :) dzięki
PirateApp,
2
wygląda ciekawie. Jedna literówka: „console.error (catch)” powinna brzmieć „console.error (err)„ Zakładam, że).
philwalk
2
Jeśli nie chcesz dodawać dodatkowego pakietu, wypróbuj poniższe rozwiązanie
@doctorlee
18
var data = fs.readFileSync('tmp/reltioconfig.json','utf8');

użyj tego do synchronicznego wywoływania pliku, bez kodowania jego wyświetlanego wyniku jako bufora.

użytkownik2266928
źródło
2
Potrzebujesz pustego wiersza przed blokami kodu, aby rozpocząć drukowanie.
royhowie
podsumowane i najlepsze!
Diament,
12

Ta linia będzie działać,

const content = fs.readFileSync('./Index.html', 'utf8');
console.log(content);
Aravin
źródło
1
Minęło 7 lat :) fs.readFileSyncjest metodą synchronizacji, więc nie ma takiej potrzeby await. Oczekiwanie jest przydatne w przypadku obietnic ( nodejs.org/api/fs.html#fs_fs_promises_api ), gdy chcesz napisać kod asynchroniczny ze składnią podobną do kodu synchronizacji.
karaxuna
@karaxuna, tak. oddalony. Właśnie dzisiaj spotkałem tę sprawę i rozwiązałem ją, używając powyższego kodu.
Aravin
1
To najprostsza odpowiedź. Jeśli nie potrzebujesz asynchronizacji, dlaczego na świecie miałbyś w ogóle mieszać się z wersją asynchroniczną, z wywołaniami zwrotnymi, asynchronizacją / czekaniem itp.? To jest odpowiednie rozwiązanie.
Master of Ducks
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
źródło
5
Proszę nie tylko wstawiać kod do swojej odpowiedzi ... wyjaśnić, dlaczego jest inny i jak rozwiązuje problem.
Studocwho,
@doctorlee To faktycznie działa dla mnie, bez żadnej biblioteki zewnętrznej. Konieczne jest wyjaśnienie.
Ashutosh Chamoli
7

sposób odczytu plików synchronizacji i asynchronizacji:

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

Węzeł Cheat Dostępny w pliku read_file .

Zeeshan Hassan Memon
źródło
7

Jak powiedziano, fs.readFilejest to działanie asynchroniczne. Oznacza to, że kiedy każesz węzłowi odczytać plik, musisz wziąć pod uwagę, że zajmie to trochę czasu, a tymczasem węzeł kontynuował działanie następującego kodu. W twoim przypadku to: console.log(content);.

To tak, jakby wysłać część kodu na długą podróż (jak czytanie dużego pliku).

Spójrz na komentarze, które napisałem:

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

Dlatego contentjest nadal pusty po zalogowaniu. węzeł nie odzyskał jeszcze zawartości pliku.

Można to rozwiązać, przechodząc console.log(content)wewnątrz funkcji oddzwaniania, zaraz po niej content = data;. W ten sposób zobaczysz dziennik, gdy węzeł skończy czytać plik i po contentotrzymaniu wartości.

Taituizm
źródło
6

Użyj wbudowanej biblioteki promisify (Node 8+), aby te stare funkcje zwrotne były bardziej eleganckie.

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);
  }
}
Dominik
źródło
Może być w pojedynczej linii const doStuff = async (filePath) => fs.readFileSync(filePath, 'utf8');, bez potrzeby użycia zawijania.
rab
1
Chodzi o to, że nie używasz wersji synchronicznej i powinieneś sobie poradzić z błędami podczas jej wywoływania
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());
});
Masoud Siahkali
źródło
2
var content;
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    content = data;
});
console.log(content);

Jest tak tylko dlatego, że węzeł jest asynchroniczny i nie będzie czekać na funkcję odczytu, a gdy tylko program się uruchomi, konsoluje wartość jako niezdefiniowaną, co jest prawdą, ponieważ do zmiennej treści nie przypisano żadnej wartości. Aby sobie z tym poradzić, możemy użyć obietnic, generatorów itp. Możemy wykorzystać obietnicę w ten sposób.

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.
})
Nouman Dilshad
źródło
2

Poniższa funkcja działa w przypadku łańcuchów asynczawijania lub obietnicythen

const readFileAsync =  async (path) => fs.readFileSync(path, 'utf8');
rab
źródło
1

możesz odczytać plik według

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

Dodając, możesz pisać do pliku,

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

a nawet połączyć to razem

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);
    }
  });
};
J. Doe
źródło
1

Mówiąc w skrócie, masz do czynienia z node.js, który ma charakter asynchroniczny.

Kiedy mówimy o asynchronizacji, mówimy o robieniu lub przetwarzaniu informacji lub danych, mając do czynienia z czymś innym. Przypominamy, że nie jest równoznaczne z równoległością.

Twój kod:

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

W przypadku próbki w zasadzie najpierw wykonuje część console.log, dlatego zmienna „content” jest niezdefiniowana.

Jeśli naprawdę potrzebujesz danych wyjściowych, zrób coś takiego:

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

To jest asynchroniczne. Trudno się przyzwyczaić, ale tak właśnie jest. Ponownie jest to szorstkie, ale szybkie wyjaśnienie, czym jest asynchronizacja.

DayIsGreen
źródło