Zapisywanie plików w Node.js

1645

Próbowałem znaleźć sposób na zapisanie pliku przy użyciu Node.js, ale bez powodzenia. Jak mogę to zrobić?

Gjorgji
źródło

Odpowiedzi:

2463

Interfejs API systemu plików zawiera wiele szczegółów . Najczęstszym sposobem jest:

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!');
Brian McKenna
źródło
25
Testowałem ten skrypt za pomocą Węzła i próbowałem zmienić ścieżkę pliku na „/ home /”, ale otrzymałem następujący błąd: { [Error: EACCES, open '/home/test.txt'] errno: 3, code: 'EACCES', path: '/home/test.txt' } Jak mogę zmodyfikować ten skrypt, aby działał poza /tmp?
Anderson Green,
129
Pamiętaj też, że możesz użyć fs.writeFileSync (...), aby osiągnąć to samo synchronicznie.
David Erwin
7
Może jest trochę stary, ale @AndersonGreen musisz poprawnie uruchomić węzeł jako root lub chmod / home, aby zezwolić na uprawnienia R / W do obecnego właściciela procesu węzła (twoja nazwa użytkownika jest trudna), abyś mógł zapisać plik
Denys Vitali
38
W rzeczywistości @DenysVitali problem polega na tym, że Jane nie powinna mieć możliwości zapisywania żadnych plików /home/.... Ogólnie ten katalog to 755 root: wheel (lub cokolwiek innego). Jeśli węzeł chce zapisać plik jako Jane, łatwiej będzie pisać /home/jane/test.txt. Zmiana /homena coś bardziej liberalnego niż 755 to ogromny błąd.
Jane Arc
7
@JaneAvriette Cóż, skoro chciał zapisać plik w /homekatalogu, zaproponowałem chmod. Wiem, że może to generować problem bezpieczeństwa. Ale cóż, jeśli użytkownik chce tam zapisać, to jest rozwiązanie. PS: Zgadzam się z tym, co powiedziałeś (:
Denys Vitali
536

Obecnie istnieją trzy sposoby zapisania pliku:

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

    Musisz poczekać na wywołanie zwrotne, aby upewnić się, że bufor jest zapisany na dysku. To nie jest buforowane.

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

    Wszystkie dane muszą być przechowywane jednocześnie; nie można wykonywać zapisów sekwencyjnych.

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

    Tworzy WriteStream, co jest wygodne, ponieważ nie trzeba czekać na oddzwonienie. Ale znowu nie jest buforowane.

A WriteStream, jak sama nazwa wskazuje, jest strumieniem. Strumień z definicji jest „buforem” zawierającym dane, które poruszają się w jednym kierunku (źródło ► miejsce docelowe). Ale zapisywalny strumień niekoniecznie jest „buforowany”. Strumień jest „buforowany” podczas zapisywania nczasów, a jednocześnie n+1strumień wysyła bufor do jądra (ponieważ jest pełny i wymaga opróżnienia).

Innymi słowy: „Bufor” to obiekt. To, czy „jest buforowane”, jest własnością tego obiektu.

Jeśli spojrzysz na kod, WriteStreamdziedziczy po zapisywalnym Streamobiekcie. Jeśli zwrócisz uwagę, zobaczysz, jak opróżniają zawartość; nie mają żadnego systemu buforowania.

Napisany ciąg znaków jest konwertowany na bufor, a następnie wysyłany do warstwy natywnej i zapisywany na dysku. Podczas pisania ciągów nie wypełniają żadnego bufora. Więc jeśli to zrobisz:

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

Robisz:

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

To trzy połączenia z warstwą we / wy. Chociaż używasz „buforów”, dane nie są buforowane. Buforowany strumień wykonałby: fs.write(new Buffer ("abc"))jedno wywołanie warstwy I / O.

Na razie w Node.js v0.12 (stabilna wersja ogłoszona 02/06/2015) obsługuje teraz dwie funkcje: cork()i uncork(). Wygląda na to, że te funkcje pozwolą wreszcie buforować / opróżniać wywołania zapisu.

Na przykład w Javie istnieje kilka klas, które zapewniają buforowane strumienie ( BufferedOutputStream, BufferedWriter...). Jeśli zapiszesz trzy bajty, te bajty zostaną zapisane w buforze (pamięci) zamiast wykonywania We / Wy tylko dla trzech bajtów. Gdy bufor jest pełny, zawartość jest opróżniana i zapisywana na dysku. Poprawia to wydajność.

Nic nie odkrywam, po prostu pamiętam, jak należy uzyskać dostęp do dysku.

Gabriel Llamas
źródło
5
+1 - ładne wyjaśnienie. W przypadku strumienia zapisu ważne jest uważne przeczytanie dokumentów. Jeśli zwraca false lub zamknięcie, ważne, aby wywołać writer.once ('drain', function () {}) lub brakowało mi linii, które nie opróżniły się po zakończeniu procesu.
bryanmac
4
masz szansę podać przykład wykorzystania cork()i uncork()dla tych z nas, którzy chcą wypróbować węzeł 0.11 przedpremierowy?
professormeowingtons
Na razie Node v0.12 jest stabilny.
sierpnia
Według analizy kodu GitHub, fs.writeFile wydaje się być najbardziej popularną z wymienionych funkcji. Oto przykłady użycia fs.writeFile w świecie rzeczywistym
drorw 18.04.19
Czy istnieją biblioteki jakości produkcji dotyczące npmwdrażania buforowanego zapisu?
nponeccop
265

Możesz oczywiście uczynić to trochę bardziej zaawansowanym. Nieblokowanie, pisanie bitów i kawałków, nie zapisywanie całego pliku na raz:

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();
});
Fredrik Andersson
źródło
17
Jaka zmienna „fd” jest przekazywana do wywołania zwrotnego dla stream.once?
Scott Tesler
1
@ScottDavidTesler deskryptor pliku, abyś mógł zamknąć strumień po zakończeniu pracy.
Alexey Kamenskiy
3
Kiedy zamknę strumień? Dlaczego to nie blokuje? Ciekawe, próbuję zapisać do pliku dziennika.
MetaGuru,
1
Nie jestem pewien, czy kiedy strumień zostanie opróżniony. Domyślam się, że istnieje możliwość opróżnienia strumienia na żądanie.
Fredrik Andersson
1
@JoLiss Będziesz musiał na to poczekać.
Fredrik Andersson,
60

Zapis synchroniczny

fs.writeFileSync (plik, dane [, opcje])

fs = require('fs');

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

Zapis asynchroniczny

fs.writeFile (plik, dane [, opcje], oddzwanianie)

fs = require('fs');

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

Gdzie

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

Warto przeczytać ten offical File System (FS) docs .

Moriarty
źródło
52
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');
        })
    });
});
Pan P.
źródło
2
pokazuje to, jak napisać plik przy użyciu operacji fs niższego poziomu. na przykład możesz zagwarantować, że plik zakończy zapisywanie na dysk i zwolni deskryptory plików.
Sean Glover
Ponieważ w tym przykładzie przesunięcie, jeśli jest ustawione na „0” (= trzeci parametr fs.write()), ten przykład działa tylko wtedy, gdy wszystko jest wystarczająco krótkie, aby można je było zapisać w jednym wywołaniu zapisu.
Manfred
30

Podobał mi się Indeks ./articles/file-system .

To zadziałało dla mnie.

Zobacz także Jak pisać pliki w 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');
});

Zawartość helloworld.txt:

Hello World!

Aktualizacja:
Jak w węźle Linuksa, pisz w bieżącym katalogu, wydaje się, że w niektórych innych tak nie jest, więc dodam ten komentarz na wszelki wypadek:
Używając tego, ROOT_APP_PATH = fs.realpathSync('.'); console.log(ROOT_APP_PATH);aby dostać się tam, gdzie zapisany jest plik.

Sérgio
źródło
Gdzie znaleźć plik helloworld.txt? Nie mogę go znaleźć w żadnym folderze ... dzięki.
Kai Feng Chew
w folderze, w którym uruchamiasz skrypt
Sérgio
To dziwne ... Po prostu nie mogę tego nigdzie znaleźć. Czy to będzie ukryte? dzięki jeszcze raz ~
Kai Feng Chew
6
Właśnie to znalazłem. Używając tego ROOT_APP_PATH = fs.realpathSync ('.'); console.log ( ROOT_APP_PATH ); żeby dostać gdzie zapisany plik. Dzięki.
Kai Feng Chew
@ Sérgio: czy musimy zamknąć plik zapisu? Dzwonię do innego procesu i otrzymuję komunikat o błędzie dotyczący tego, że plik zaczyna być używany przez inny proces.
Amir,
23

Odpowiedzi są opatrzone datą, a nowszym sposobem na to jest:

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

zobacz dokumenty tutaj, aby uzyskać więcej informacji

TrevTheDev
źródło
1
(node:23759) ExperimentalWarning: The fs.promises API is experimental
jgraup
@jgraup: używasz najnowszej wersji węzła?
TrevTheDev
Węzełv10.15.0
jgraup
7
Funkcja zamykania musi być asynchroniczna, inaczej to nie zadziała.
Zimano
1
@wintercounter To całkiem słodkie!
Zimano
18

Wiem, że pytanie dotyczące „zapisu”, ale w bardziej ogólnym znaczeniu, „append” może być przydatne w niektórych przypadkach, ponieważ można łatwo użyć go w pętli, aby dodać tekst do pliku (niezależnie od tego, czy plik istnieje). Użyj „\ n”, jeśli chcesz dodać linie, np .:

var fs = require('fs');
for (var i=0; i<10; i++){
    fs.appendFileSync("junk.csv", "Line:"+i+"\n");
}
Astra Bear
źródło
Ponieważ jest już dostępny, zalecam używanie constzamiast var, tj. W const fs = require('fs');celu uniknięcia niepożądanych efektów ubocznych, w szczególności jeśli pracujesz z nieco większą bazą kodu.
Manfred
10

OK, jest to dość proste, ponieważ Node ma wbudowaną funkcjonalność do tego, nazywa się to, fsco oznacza system plików i, w zasadzie, moduł systemu plików NodeJS ...

Więc najpierw wymagaj tego w pliku server.js w następujący sposób:

var fs = require('fs');

fsma kilka metod zapisu do pliku, ale moim preferowanym sposobem jest użycie appendFile, to doda rzeczy do pliku, a jeśli plik nie istnieje, utworzy jeden, kod może wyglądać jak poniżej:

fs.appendFile('myFile.txt', 'Hi Ali!', function (err) {
  if (err) throw err;
  console.log('Thanks, It\'s saved to the file!');
});
Alireza
źródło
3
pojedynczy cytat w ciągu powinien być poprzedzony znakiem ucieczki.
Poskramiacz
8
 var fs = require('fs');
 fs.writeFile(path + "\\message.txt", "Hello", function(err){
 if (err) throw err;
  console.log("success");
}); 

Na przykład: odczytaj plik i zapisz do innego pliku:

  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");
                            });
                        }
                });
Masoud Siahkali
źródło
Gdzie zapisujesz dane w „to.text”?
Ravi Shanker Reddy
Co ta odpowiedź dodaje do wielu już istniejących odpowiedzi writeFile?
Dan Dascalescu
7

Możesz pisać do pliku za pomocą modułu fs (system plików).

Oto przykład, jak możesz to zrobić:

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

Możesz także pozbyć się tej struktury kodu wywołania zwrotnego wewnątrz wywołania zwrotnego, używając Obietnic i async/ lub awaitinstrukcji. Spowoduje to, że struktura kodu asynchronicznego będzie o wiele bardziej płaska. Do tego służy przydatna funkcja util.promisify (oryginalna) . Pozwala nam przejść z oddzwaniania do obietnic. Spójrz na przykład z fsfunkcjami poniżej:

// 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);
}
Oleksii Trekhleb
źródło
1
Dlaczego te fragmenty, a nie fragmenty kodu? I tak nigdy nie będą mogły działać w przeglądarce.
Zimano
@Zimano Jak rozumiem, pytanie dotyczyło nodejów, więc nie musi działać w przeglądarce.
Manfred,
1
@Manfred Dokładnie! Myślę, że źle zrozumiałeś, co próbowałem powiedzieć; nie ma sensu mieć urywków, ponieważ to nodejs!
Zimano
4

Tutaj używamy w + do odczytu / zapisu obu akcji, a jeśli ścieżka pliku nie zostanie znaleziona, zostanie utworzona automatycznie.

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

Treść oznacza, co musisz zapisać do pliku i jego długość, „content.length”.

Gunjan Patel
źródło
2

Oto przykład, jak odczytać plik csv z lokalnego i zapisać plik csv do lokalnego.

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()
KARTHIKEYAN.A
źródło
1
Wprowadza to wszelkiego rodzaju komplikacje (MongoClient, JSON itp.), Które nie dotyczą pytania.
Dan Dascalescu
2

fs.createWriteStream(path[,options])

optionsmoże również zawierać startopcję umożliwiającą zapis danych w pewnej pozycji poza początkiem pliku. Modyfikowanie pliku zamiast zastępowania może wymagać flagstrybu r+raczej niż trybu domyślnego w. Kodowanie może być dowolnym z zaakceptowanych przez bufor .

Jeśli autoClosejest ustawiony na true (zachowanie domyślne) 'error'lub 'finish'deskryptor pliku zostanie zamknięty automatycznie. Jeśli autoClosema wartość false, deskryptor pliku nie zostanie zamknięty, nawet jeśli wystąpi błąd. Aplikacja jest odpowiedzialna za jej zamknięcie i upewnienie się, że nie ma wycieku deskryptora pliku.

Podobnie jak ReadStream , jeśli fdjest określony, WriteStream zignoruje pathargument i użyje określonego deskryptora pliku. Oznacza to, że żadne 'open'zdarzenie nie będzie emitowane. fdpowinien blokować; nieblokujące fds należy przekazać do net.Socket .

Jeśli optionsjest łańcuchem, to określa kodowanie.

Po przeczytaniu tego długiego artykułu. Powinieneś zrozumieć, jak to działa. Oto przykład 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');

źródło
createWriteStreambyło już wspomniane w wielu latach odpowiedzi przed tym.
Dan Dascalescu
0

Możesz użyć biblioteki easy-file-manager

zainstaluj najpierw z npm npm install easy-file-manager

Próbka do przesłania i usunięcia plików

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);
});
Christoper
źródło
2
This modules is created to save and remove files.. Nie odpowiedź.
Zielony,
-1

Możesz zapisać w pliku za pomocą następującego przykładu kodu:

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.');
      }
    });
  }
});
Mudassir
źródło
1
writeFilejuż wiele lat temu udzielono odpowiedzi jako odpowiedzi. Co dodaje ta odpowiedź?
Dan Dascalescu
Również dlaczego otwierasz plik? Czy odpowiedź nie powinna dotyczyć zapisywania plików?
Michał