Запис файлів у Node.js


1645

Я намагався знайти спосіб запису у файл під час використання Node.js, але не мав успіху. Як я можу це зробити?

Відповіді:


2463

В API файлової системи є багато деталей . Найпоширеніший спосіб:

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

25
Я перевірив цей скрипт за допомогою Node, і я спробував змінити шлях до файлу на "/ home /", але я отримав таку помилку: { [Error: EACCES, open '/home/test.txt'] errno: 3, code: 'EACCES', path: '/home/test.txt' } Як я можу змінити цей скрипт, щоб він працював поза /tmp?
Андерсон Грін

129
Також зауважте, що ви можете використовувати fs.writeFileSync (...), щоб виконати те саме, що синхронізується.
Девід Ервін

7
Можливо, він трохи старий, але @AndersonGreen вам потрібно запустити вузол як root або chmod / home належним чином, щоб дозволити R / W дозволити поточному власнику процесу вузла (ваше ім'я користувача жорстке), щоб ви могли написати файл
Denys Vitali

38
Власне, @DenysVitali, проблема полягає в тому, що Джейн не має змоги записувати жодні файли в /home/.... Як правило, цей каталог має 755 root: wheel (або що завгодно). Якщо вузол хоче записати файл як jane, записати його буде простіше /home/jane/test.txt. Перехід /homeна щось більш дозвільне, ніж 755, - це величезна помилка.
дуга jane

7
@JaneAvriette Ну, оскільки він хотів зберегти файл у /homeкаталозі, я запропонував chmod його. Я знаю, що це може призвести до проблеми безпеки. Але добре, якщо користувач хоче зберегти там, це рішення. PS: Я згоден з тим, що ви сказали (:
Denys Vitali

536

В даний час існує три способи написання файлу:

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

    Вам потрібно дочекатися зворотного дзвінка, щоб переконатися, що буфер записаний на диск. Це не буферно.

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

    Усі дані повинні зберігатися одночасно; Ви не можете виконувати послідовне записування.

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

    Створюється WriteStream, що зручно, оскільки не потрібно чекати зворотного дзвінка. Але знову ж таки, це не буферно.

А WriteStream, як видно з назви, - це потік. Потік за визначенням - це "буфер", що містить дані, які рухаються в одному напрямку (джерело ► призначення). Але потік, що записується, не обов'язково "буферний". Потік "буферизується", коли ви пишете nрази, і в той час n+1потік надсилає буфер до ядра (тому що він повний і його потрібно промити).

Іншими словами: "Буфер" - це об'єкт. Незалежно від того, "він буферизований" - це властивість цього об'єкта.

Якщо ви подивитеся на код, то WriteStreamспадкує від Streamоб'єкта, що записується . Якщо ви звернете увагу, ви побачите, як вони стирають вміст; у них немає системи буферизації.

Якщо ви пишете рядок, вона перетворюється в буфер, а потім надсилається в рідний шар і записується на диск. Під час написання рядків вони не заповнюють жодного буфера. Отже, якщо ви робите:

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

Ти робиш:

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

Це три виклики до шару вводу / виводу. Хоча ви використовуєте "буфери", дані не буферні. Буферизований потік зробив би:, fs.write(new Buffer ("abc"))один дзвінок на рівень вводу / виводу.

Відтепер у Node.js v0.12 (стабільна версія оголошена 02.06.2015) тепер підтримується дві функції: cork()і uncork(). Здається, що ці функції, нарешті, дозволять вам захистити або записувати дзвінки запису.

Наприклад, у Java є деякі класи, які надають буферизовані потоки ( BufferedOutputStream, BufferedWriter...). Якщо ви пишете три байти, ці байти будуть зберігатися в буфері (пам'яті), а не робити дзвінок вводу-виводу лише на три байти. Коли буфер заповнений, вміст очищається та зберігається на диску. Це покращує продуктивність.

Я нічого не відкриваю, просто пам'ятаю, як слід робити доступ до диска.


5
+1 - приємне пояснення. Для потоку записів важливо уважно прочитати документи. Якщо повертається помилково або закривається, важливо зателефонувати по письменнику.once ('drain', function () {}) або я пропустив рядки, які не дренувалися, коли процес закінчився.
bryanmac

4
будь-який шанс ви можете навести приклад того, як використовувати cork()та uncork()для тих із нас, хто хоче спробувати вузол попереднього випуску 0.11?
Professormeowingtons

На сьогодні Node v0.12 стабільний.
Август

Відповідно до аналізу коду від GitHub, здається, fs.writeFile є найпопулярнішою із згаданих вами функцій. Ось приклади реального світу для використання fs.writeFile
drorw

Чи існують бібліотеки якості виробництва для npmвпровадження буферизованого написання?
nponeccop

265

Ви, звичайно, можете зробити це трохи більш вдосконаленим. Не блокуючи, записуйте шматочки та фрагменти, не записуйте весь файл одразу:

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
Що змінна 'fd' передається у зворотній виклик для stream.once?
Скотт Теслер

1
Дескриптор файлу @ScottDavidTesler, тому ви зможете закрити потік після того, як ви зробили це з ним.
Олексій Каменський

3
Коли я закриваю потік? Чому це не блокує? Просто цікаво, я намагаюся записати файл журналу.
MetaGuru

1
Я не впевнений, якщо при потоку розмивається. Я здогадуюсь, що існує можливість змити потік на вимогу.
Фредрік Андерссон

1
@JoLiss На це доведеться чекати.
Фредрік Андерссон

60

Синхронне записування

fs.writeFileSync (файл, дані [, параметри])

fs = require('fs');

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

Асинхронний запис

fs.writeFile (файл, дані [, параметри], зворотний дзвінок)

fs = require('fs');

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

Де

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

Варто прочитати в OFFICAL File System (ФС) DOCS .


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

2
це демонструє, як записати файл за допомогою операцій fs нижнього рівня. наприклад, ви можете гарантувати, коли файл закінчив записувати на диск і випустив дескриптори файлів.
Шон Гловер

Оскільки в цьому прикладі зміщення, якщо встановлено значення '0' (= третій параметр fs.write()), цей приклад працює лише в тому випадку, якщо все достатньо коротке, щоб записатись в один виклик запису.
Манфред

30

Мені сподобався індекс ./articles/file-system .

Це працювало для мене.

Дивіться також Як я можу записати файли в 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');
});

Зміст helloworld.txt:

Hello World!

Оновлення:
як і в Linux-вузлі пишуть у поточному каталозі, схоже, в деяких інших немає, тому я додаю цей коментар про всяк випадок:
Використовуючи це, ROOT_APP_PATH = fs.realpathSync('.'); console.log(ROOT_APP_PATH);щоб дістатись, де записаний файл.


Де знайти файл helloworld.txt? Я не можу його знайти в жодних папках ... дякую.
Kai Feng Chew

в папці , яку ви запустите скрипт
Серджіу

Це дивно ... Я просто ніде його не можу знайти. Чи буде це приховано? ще раз дякую ~
Kai Feng Chew

6
Я щойно це знайшов. Використовуючи цей ROOT_APP_PATH = fs.realpathSync ('.'); console.log ( ROOT_APP_PATH ); щоб отримати мій, де записаний файл. Дякую.
Кай Фенг Чеу

@ Серхіо: чи нам потрібно закрити файл запису? Я закликаю інший процес, і я отримую повідомлення про помилку щодо файлу, який починає використовувати якийсь інший процес.
Амір

23

Надані відповіді датовані, і новіший спосіб зробити це:

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

див. документи тут для отримання додаткової інформації


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

@jgraup: ви використовуєте останню версію вузла?
TrevTheDev

Вузолv10.15.0
jgraup

7
Функція закривання повинна бути асинхронізованою, інакше це не працюватиме.
Zimano

1
@wintercounter Це дуже солодко!
Зімано

18

Я знаю, що запитання про "написати", але в більш загальному сенсі "додавання" може бути корисним в деяких випадках, оскільки це легко використовувати в циклі, щоб додати текст у файл (чи існує файл чи ні). Використовуйте "\ n", якщо ви хочете додати рядки, наприклад:

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

Оскільки він доступний, я рекомендую використовувати constзамість нього var, тобто const fs = require('fs');уникати небажаних побічних ефектів, особливо якщо ви працюєте з дещо більшою базою коду.
Манфред

10

Гаразд, це дуже просто, оскільки Node має вбудований функціонал для цього, він називається, fsякий означає файлову систему і, в основному, модуль файлової системи NodeJS ...

Тому спочатку вимагайте цього у вашому файлі server.js таким чином:

var fs = require('fs');

fsє кілька способів зробити запис у файл, але моїм кращим способом є використання appendFile, це додасть файл до файлу, і якщо файл не існує, створить його, код може бути таким, як нижче:

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

3
одиничну цитату в рядку слід уникати.
Тамер

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

Наприклад: прочитати файл і записати в інший файл:

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

Де ви записуєте дані в "to.text" ??
Раві Шенкер Редді

Що ця відповідь додає до безлічі вже існуючих відповідей writeFile?
Дан Даскалеску

7

Ви можете записати у файл, використовуючи модуль fs (файлова система).

Ось приклад того, як ви можете це зробити:

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

Можливо, ви також хочете позбутися цієї структури коду зворотного виклику всередині виклику, використовуючи Обіцянки та async/ awaitоператори. Це зробить асинхронну структуру коду набагато більш простою. Для цього може бути використана зручна функція util.promisify (оригінальна) . Це дозволяє нам переходити від зворотних викликів до обіцянок. Погляньте на приклад із fsнаведеними нижче функціями:

// 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
Чому це фрагменти, а не фрагменти коду? Вони ніколи не зможуть запуститись у веб-переглядачі.
Zimano

@ Zimano Як я розумію, питання стосувалося nodejs, тому не потрібно мати змогу запускатись у браузері.
Манфред

1
@Manfred Рівно! Я думаю, ти неправильно зрозумів, що я намагався сказати; немає сенсу робити фрагменти, оскільки це nodejs!
Zimano

4

Тут ми використовуємо w + для читання / запису обох дій, і якщо шлях до файлу не знайдений, він буде створений автоматично.

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

Вміст означає те, що потрібно записати у файл та його довжину, 'content.length'.


2

Ось зразок того, як читати файл csv з локального та записувати файл csv у локальний.

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
Це спричиняє всілякі ускладнення (MongoClient, JSON тощо), які не стосуються цього питання.
Дан Даскалеску

2

fs.createWriteStream(path[,options])

optionsможе також включати startопцію, щоб дозволити записувати дані в деяку позицію, що передує початку файлу. Для зміни файлу, а не заміни його може знадобитися flagsрежим, r+а не режим за замовчуванням w. Кодування може бути будь-яким із прийнятих Buffer .

Якщо autoCloseвстановлено значення true (поведінка за замовчуванням) 'error'або 'finish'дескриптор файлу закриється автоматично. ЯкщоautoClose false, дескриптор файлу не закриється, навіть якщо є помилка. Потрібно закрити програму та переконатися у відсутності витоку дескриптора файлу.

Як і ReadStream , якщо fdвін вказаний, WriteStream ігнорує pathаргумент і використовуватиме вказаний дескриптор файлу. Це означає, що жодна 'open'подія не передаватиметься. fdмає бути блокуючим; неблокуючі fds повинні бути передані до net.Socket .

Якщо optionsце рядок, то він визначає кодування.

Після, прочитавши цю довгу статтю. Ви повинні зрозуміти, як це працює. Отже, ось приклад 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вже згадувалося у кількох роках відповідей до цього.
Дан Даскалеску

0

Ви можете використовувати бібліотеку easy-file-manager

встановити спочатку з npm npm install easy-file-manager

Зразок для завантаження та видалення файлів

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.. Не відповідь.
Зелений

-1

Ви можете записати у файл на прикладі наступного коду:

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вже давались як відповідь кілька разів, років тому. Що додає ця відповідь?
Дан Даскалеску

Також чому ви відкриєте файл? Чи не повинна відповідь стосуватися написання файлів?
Міхал
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.