Node.js
Ввод / вывод файловой системы
Поиск…
замечания
В Node.js операции с ресурсами, такие как ввод-вывод, выполняются асинхронно , но имеют синхронный аналог (например, существует fs.readFile
а его аналог - fs.readFileSync
). Поскольку Node является однопоточным, вы должны быть осторожны при использовании синхронных операций, поскольку они блокируют весь процесс.
Если процесс блокируется синхронной операцией, весь цикл выполнения (включая цикл событий) останавливается. Это означает, что другой асинхронный код, включая события и обработчики событий, не будет запускаться, и ваша программа будет продолжать ждать завершения одной операции блокировки.
Существуют соответствующие применения как для синхронных, так и для асинхронных операций, но необходимо принять меры к тому, чтобы они использовались надлежащим образом.
Запись в файл с использованием writeFile или writeFileSync
var fs = require('fs');
// Save the string "Hello world!" in a file called "hello.txt" in
// the directory "/tmp" using the default encoding (utf8).
// This operation will be completed in background and the callback
// will be called when it is either done or failed.
fs.writeFile('/tmp/hello.txt', 'Hello world!', function(err) {
// If an error occurred, show it and return
if(err) return console.error(err);
// Successfully wrote to the file!
});
// Save binary data to a file called "binary.txt" in the current
// directory. Again, the operation will be completed in background.
var buffer = new Buffer([ 0x48, 0x65, 0x6c, 0x6c, 0x6f ]);
fs.writeFile('binary.txt', buffer, function(err) {
// If an error occurred, show it and return
if(err) return console.error(err);
// Successfully wrote binary contents to the file!
});
fs.writeFileSync
ведет себя аналогично fs.writeFile
, но не выполняет обратный вызов, поскольку он завершает синхронно и, следовательно, блокирует основной поток. Большинство разработчиков node.js предпочитают асинхронные варианты, которые практически не задерживают выполнение программы.
Примечание. Блокирование основного потока - это плохая практика в node.js. Синхронная функция должна использоваться только при отладке или когда другие параметры недоступны.
// Write a string to another file and set the file mode to 0755
try {
fs.writeFileSync('sync.txt', 'anni', { mode: 0o755 });
} catch(err) {
// An error occurred
console.error(err);
}
Асинхронно читать из файлов
Используйте модуль файловой системы для всех операций с файлами:
const fs = require('fs');
С кодировкой
В этом примере прочитайте hello.txt
из каталога /tmp
. Эта операция будет завершена в фоновом режиме, и обратный вызов будет выполняться при завершении или сбое:
fs.readFile('/tmp/hello.txt', { encoding: 'utf8' }, (err, content) => {
// If an error occurred, output it and return
if(err) return console.error(err);
// No error occurred, content is a string
console.log(content);
});
Без кодирования
Прочитайте бинарный файл binary.txt
из текущего каталога, асинхронно в фоновом режиме. Обратите внимание, что мы не устанавливаем параметр «encoding» - это предотвращает декодирование содержимого Node.js в строку:
fs.readFile('binary', (err, binaryContent) => {
// If an error occurred, output it and return
if(err) return console.error(err);
// No error occurred, content is a Buffer, output it in
// hexadecimal representation.
console.log(content.toString('hex'));
});
Относительные пути
Имейте в виду, что в общем случае ваш скрипт может запускаться с произвольным текущим рабочим каталогом. Чтобы обратиться к файлу относительно текущего скрипта, используйте __dirname
или __filename
:
fs.readFile(path.resolve(__dirname, 'someFile'), (err, binaryContent) => {
//Rest of Function
}
Список содержимого каталога с помощью readdir или readdirSync
const fs = require('fs');
// Read the contents of the directory /usr/local/bin asynchronously.
// The callback will be invoked once the operation has either completed
// or failed.
fs.readdir('/usr/local/bin', (err, files) => {
// On error, show it and return
if(err) return console.error(err);
// files is an array containing the names of all entries
// in the directory, excluding '.' (the directory itself)
// and '..' (the parent directory).
// Display directory entries
console.log(files.join(' '));
});
Синхронный вариант доступен как readdirSync
который блокирует основной поток и, следовательно, предотвращает одновременное выполнение асинхронного кода. Большинство разработчиков избегают синхронных функций ввода-вывода для повышения производительности.
let files;
try {
files = fs.readdirSync('/var/tmp');
} catch(err) {
// An error occurred
console.error(err);
}
Использование генератора
const fs = require('fs');
// Iterate through all items obtained via
// 'yield' statements
// A callback is passed to the generator function because it is required by
// the 'readdir' method
function run(gen) {
var iter = gen((err, data) => {
if (err) { iter.throw(err); }
return iter.next(data);
});
iter.next();
}
const dirPath = '/usr/local/bin';
// Execute the generator function
run(function* (resume) {
// Emit the list of files in the directory from the generator
var contents = yield fs.readdir(dirPath, resume);
console.log(contents);
});
Чтение из файла синхронно
Для любых операций с файлами вам понадобится модуль файловой системы:
const fs = require('fs');
Чтение строки
fs.readFileSync
ведет себя аналогично fs.readFile
, но не выполняет обратный вызов, поскольку он завершает синхронно и поэтому блокирует основной поток. Большинство разработчиков node.js предпочитают асинхронные варианты, которые практически не задерживают выполнение программы.
Если указан параметр encoding
, будет возвращена строка, иначе Buffer
будет возвращен.
// Read a string from another file synchronously
let content;
try {
content = fs.readFileSync('sync.txt', { encoding: 'utf8' });
} catch(err) {
// An error occurred
console.error(err);
}
Удаление файла с помощью unlink или unlinkSync
Удалите файл асинхронно:
var fs = require('fs');
fs.unlink('/path/to/file.txt', function(err) {
if (err) throw err;
console.log('file deleted');
});
Вы также можете удалить его синхронно *:
var fs = require('fs');
fs.unlinkSync('/path/to/file.txt');
console.log('file deleted');
* избегайте синхронных методов, потому что они блокируют весь процесс до завершения выполнения.
Чтение файла в буфер с использованием потоков
Хотя чтение содержимого из файла уже асинхронно с использованием fs.readFile()
, иногда мы хотим получить данные в потоке по сравнению с простым обратным вызовом. Это позволяет нам передавать эти данные в другие местоположения или обрабатывать их, как это происходит в каждом случае одновременно.
const fs = require('fs');
// Store file data chunks in this array
let chunks = [];
// We can use this variable to store the final data
let fileBuffer;
// Read file into stream.Readable
let fileStream = fs.createReadStream('text.txt');
// An error occurred with the stream
fileStream.once('error', (err) => {
// Be sure to handle this properly!
console.error(err);
});
// File is done being read
fileStream.once('end', () => {
// create the final data Buffer from data chunks;
fileBuffer = Buffer.concat(chunks);
// Of course, you can do anything else you need to here, like emit an event!
});
// Data is flushed from fileStream in chunks,
// this callback will be executed for each chunk
fileStream.on('data', (chunk) => {
chunks.push(chunk); // push data chunk to array
// We can perform actions on the partial data we have so far!
});
Проверка разрешений файла или каталога
fs.access()
определяет, существует ли путь и какие права доступа пользователю к файлу или каталогу на этом пути. fs.access
не возвращает результат скорее, если он не возвращает ошибку, путь существует, и у пользователя есть необходимые разрешения.
Режимы разрешений доступны как свойство объекта fs
, fs.constants
-
fs.constants.F_OK
- Имеет разрешения на чтение / запись / выполнение (если неfs.constants.F_OK
режим, это значение по умолчанию) -
fs.constants.R_OK
- имеет разрешения на чтение -
fs.constants.W_OK
- имеет разрешения на запись -
fs.constants.X_OK
- имеет разрешения на выполнение (работает так же, какfs.constants.F_OK
в Windows)
Асинхронный
var fs = require('fs');
var path = '/path/to/check';
// checks execute permission
fs.access(path, fs.constants.X_OK, (err) => {
if (err) {
console.log("%s doesn't exist", path);
} else {
console.log('can execute %s', path);
}
});
// Check if we have read/write permissions
// When specifying multiple permission modes
// each mode is separated by a pipe : `|`
fs.access(path, fs.constants.R_OK | fs.constants.W_OK, (err) => {
if (err) {
console.log("%s doesn't exist", path);
} else {
console.log('can read/write %s', path);
}
});
Синхронно
fs.access
также имеет синхронную версию fs.accessSync
. При использовании fs.accessSync
вы должны заключить его в блок try / catch.
// Check write permission
try {
fs.accessSync(path, fs.constants.W_OK);
console.log('can write %s', path);
}
catch (err) {
console.log("%s doesn't exist", path);
}
Избегание условий гонки при создании или использовании существующего каталога
Из-за асинхронного характера узла, создания или использования каталога сначала:
- проверяя его существование с помощью
fs.stat()
, тогда - создавая или используя его в зависимости от результатов проверки существования,
может привести к состоянию гонки, если папка создается между временем проверки и временем создания. Метод ниже обертывает fs.mkdir()
и fs.mkdirSync()
в fs.mkdirSync()
ошибках, которые пропускают исключение, если его код EEXIST
(уже существует). Если ошибка - это что-то еще, например EPERM
(pemission denied), пропустите или передайте ошибку, как это делают нативные функции.
Асинхронная версия с fs.mkdir()
var fs = require('fs'); function mkdir (dirPath, callback) { fs.mkdir(dirPath, (err) => { callback(err && err.code !== 'EEXIST' ? err : null); }); } mkdir('./existingDir', (err) => { if (err) return console.error(err.code); // Do something with `./existingDir` here });
Синхронная версия с fs.mkdirSync()
function mkdirSync (dirPath) { try { fs.mkdirSync(dirPath); } catch(e) { if ( e.code !== 'EEXIST' ) throw e; } } mkdirSync('./existing-dir'); // Do something with `./existing-dir` now
Проверка наличия файла или каталога
Асинхронный
var fs = require('fs');
fs.stat('path/to/file', function(err) {
if (!err) {
console.log('file or directory exists');
}
else if (err.code === 'ENOENT') {
console.log('file or directory does not exist');
}
});
Синхронно
здесь мы должны обернуть вызов функции в блок try/catch
для обработки ошибки.
var fs = require('fs');
try {
fs.statSync('path/to/file');
console.log('file or directory exists');
}
catch (err) {
if (err.code === 'ENOENT') {
console.log('file or directory does not exist');
}
}
Клонирование файла с использованием потоков
Эта программа иллюстрирует, как можно скопировать файл с помощью считываемых и записываемых потоков с помощью функций createReadStream()
и createWriteStream()
предоставляемых модулем файловой системы.
//Require the file System module
var fs = require('fs');
/*
Create readable stream to file in current directory (__dirname) named 'node.txt'
Use utf8 encoding
Read the data in 16-kilobyte chunks
*/
var readable = fs.createReadStream(__dirname + '/node.txt', { encoding: 'utf8', highWaterMark: 16 * 1024 });
// create writable stream
var writable = fs.createWriteStream(__dirname + '/nodeCopy.txt');
// Write each chunk of data to the writable stream
readable.on('data', function(chunk) {
writable.write(chunk);
});
Копирование файлов по потокам трубопроводов
Эта программа копирует файл с помощью считываемого и записываемого потока с помощью функции pipe()
предоставляемой классом потока
// require the file system module
var fs = require('fs');
/*
Create readable stream to file in current directory named 'node.txt'
Use utf8 encoding
Read the data in 16-kilobyte chunks
*/
var readable = fs.createReadStream(__dirname + '/node.txt', { encoding: 'utf8', highWaterMark: 16 * 1024 });
// create writable stream
var writable = fs.createWriteStream(__dirname + '/nodePipe.txt');
// use pipe to copy readable to writable
readable.pipe(writable);
Изменение содержимого текстового файла
Пример. Он заменит слово email
на name
в текстовом файле index.txt
с простой replace(/email/gim, 'name')
RegExp replace(/email/gim, 'name')
var fs = require('fs');
fs.readFile('index.txt', 'utf-8', function(err, data) {
if (err) throw err;
var newValue = data.replace(/email/gim, 'name');
fs.writeFile('index.txt', newValue, 'utf-8', function(err, data) {
if (err) throw err;
console.log('Done!');
})
})
Определение количества строк текстового файла
app.js
const readline = require('readline');
const fs = require('fs');
var file = 'path.to.file';
var linesCount = 0;
var rl = readline.createInterface({
input: fs.createReadStream(file),
output: process.stdout,
terminal: false
});
rl.on('line', function (line) {
linesCount++; // on each linebreak, add +1 to 'linesCount'
});
rl.on('close', function () {
console.log(linesCount); // print the result when the 'close' event is called
});
Использование:
узловое приложение
Чтение файла по строкам
app.js
const readline = require('readline');
const fs = require('fs');
var file = 'path.to.file';
var rl = readline.createInterface({
input: fs.createReadStream(file),
output: process.stdout,
terminal: false
});
rl.on('line', function (line) {
console.log(line) // print the content of the line on each linebreak
});
Использование:
узловое приложение