Чтение файлов с помощью Node.js

Одна из самых распространенных вещей, которые вы захотите сделать практически с любым языком программирования, - это открыть и прочитать файл. С большинством языков это довольно просто, но для ветеранов JavaScript это может показаться немного странным. В течение стольких лет JavaScript был доступен только в браузере, поэтому интерфейсные разработчики могут быть знакомы только с FileReader API [http://www.htmlgoodies.com/beyond/javascript/read-text-files-using-the- javascript-filereader.html # fbid = PfBQ7GOxcEB] или аналогичный. Node.js, как вы наверное

Одна из самых распространенных вещей, которые вы захотите сделать практически с любым языком программирования, - это открыть и прочитать файл. С большинством языков это довольно просто, но для ветеранов JavaScript это может показаться немного странным. В течение стольких лет JavaScript был доступен только в браузере, поэтому интерфейсные разработчики могут быть знакомы только с FileReader API или аналогичным.

Node.js, как вы, наверное, знаете, сильно отличается от обычного JavaScript в браузере. Он имеет собственный набор библиотек, предназначенных для обработки задач ОС и файловой системы, таких как открытие и чтение файлов. В этой статье я покажу вам, как использовать Node.js для чтения файлов. В частности, для этого мы будем использовать модуль fs.

Есть два способа открыть и прочитать файл с помощью модуля fs

  • Загрузить все содержимое сразу (буферизация)
  • Поэтапная загрузка содержимого (потоковая передача)

Каждый из этих методов будет объяснен в следующих двух разделах.

Буферизация содержимого с помощью fs.readFile

Это наиболее распространенный способ чтения файла с помощью Node.js, особенно для начинающих, благодаря его простоте и удобству. Хотя, как вы поймете в следующем разделе, он не обязательно самый лучший или самый эффективный.

Вот быстрый пример использования fs.readFile :

 var fs = require('fs'); 
 
 fs.readFile('my-file.txt', 'utf8', function(err, data) { 
 if (err) throw err; 
 console.log(data); 
 }); 

data для обратного вызова содержит полное содержимое файла, представленного в виде строки в формате utf8 Если вы полностью опустите utf8 , метод просто вернет необработанное содержимое в объекте Buffer. Удалив utf8 в приведенном выше коде (и предполагая, что my-file.txt содержит строку «Привет!»), Мы получим следующий вывод:

 $ node read-file.js 
 <Buffer 48 65 79 20 74 68 65 72 65 21> 

Вы могли заметить, что fs.readFile , что означает, что этот метод выполняется асинхронно. Это следует использовать всякий раз, когда это возможно, чтобы избежать блокировки основного потока выполнения, но иногда вам нужно делать что-то синхронно, и в этом случае Node предоставляет вам метод readFileSync.

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

Вот как загрузить файл синхронно с Node:

 var fs = require('fs'); 
 
 try { 
 var data = fs.readFileSync('my-file.txt', 'utf8'); 
 console.log(data); 
 } catch(e) { 
 console.log('Error:', e.stack); 
 } 

Обратите внимание, что с блокирующим (синхронным) вызовом мы должны использовать try...catch для обработки любых ошибок, в отличие от неблокирующей (асинхронной) версии, где ошибки просто передавались нам в качестве аргументов.

За исключением способа, которым эти методы возвращают данные и обрабатывают ошибки, они работают почти так же.

Потоковая передача содержимого с помощью fs.createReadStream

Второй способ открыть и прочитать файл - открыть его как Stream с помощью метода fs.createReadStream. Все потоки Node являются экземплярами объекта EventEmitter , что позволяет вам подписываться на важные события.

Читаемый объект потока может быть полезен по множеству причин, некоторые из которых включают:

  • Меньший объем памяти . Поскольку данные целевого файла загружаются кусками, не так много памяти требуется для хранения данных в буфере.
  • Более быстрое время отклика . Для приложений, чувствительных ко времени, время между запросом и ответом имеет решающее значение. Потоки сокращают время отклика (особенно для больших файлов), поскольку им не нужно ждать загрузки всего файла перед возвратом данных.
  • Данные трубопроводов . Абстракция потока позволяет вам использовать общий интерфейс между производителями и потребителями данных для передачи этих данных по каналам. Это очень похоже на концепцию конвейера Unix.

Хотя на самом деле использовать потоки не так уж сложно, они могут быть немного пугающими и не столь интуитивно понятны, как метод fs.readFile Вот привет, мир потоковой передачи файлов:

 var fs = require('fs'); 
 
 var data = ''; 
 
 var readStream = fs.createReadStream('my-file.txt', 'utf8'); 
 
 readStream.on('data', function(chunk) { 
 data += chunk; 
 }).on('end', function() { 
 console.log(data); 
 }); 

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

Обратите внимание, что пример, который я показал выше, в основном противоречит цели использования потока, поскольку мы все равно собираем данные в буфере (переменной), но, по крайней мере, он дает вам представление о том, как они работают. Лучший пример, показывающий сильные стороны файловых потоков, можно увидеть здесь, в маршруте Express, который обрабатывает запрос файла:

 var fs = require('fs'); 
 var path = require('path'); 
 var http = require('http'); 
 
 var staticBasePath = './static'; 
 
 var staticServe = function(req, res) { 
 var fileLoc = path.resolve(staticBasePath); 
 fileLoc = path.join(fileLoc, req.url); 
 
 var stream = fs.createReadStream(fileLoc); 
 
 stream.on('error', function(error) { 
 res.writeHead(404, 'Not Found'); 
 res.end(); 
 }); 
 
 stream.pipe(res); 
 }; 
 
 var httpServer = http.createServer(staticServe); 
 httpServer.listen(8080); 

Все, что мы здесь делаем, это открываем файл с помощью fs.createReadStream и перенаправляем его объекту ответа res . Мы даже можем подписаться на сообщения error и обрабатывать их по мере их возникновения. Это гораздо лучший метод работы с файлами, если вы научитесь его правильно использовать. Чтобы получить более полный пример и объяснение приведенного выше кода, ознакомьтесь с этой статьей о создании статических файловых серверов с помощью Node .

Заключение

Из этой статьи вы должны были изучить основы чтения файлов, а также некоторые расширенные методы загрузки с использованием объектов Stream. Ключевым моментом является знание того, когда их использовать, и это следует тщательно продумать для приложений с ограниченным объемом памяти или временем.

Какой метод работы с файлами вы предпочитаете? Как вы использовали Streams в прошлом? Дайте нам знать об этом в комментариях!

comments powered by Disqus