Представьте, что у вас есть каталог с заархивированными файлами, и вы хотите их все распаковать. Этого можно добиться вручную, щелкнув все из них, чтобы распаковать их, но это также можно сделать с помощью простого скрипта NodeJS. На днях я проделал это с десятками файлов, загруженных с AWS S3, и на удивление не смог найти в Интернете четкого примера того, что именно я хотел, поэтому решил написать эту статью.

Настраивать

Если вы хотите создать несколько заархивированных файлов для практики, следуйте приведенным ниже инструкциям, чтобы создать новый проект Node и создать файлы практики:

$ mkdir zipping-practice

$ cd zipping-practice

$ touch index.js

$ mkdir data

$ echo 'whatever text you want' > data/file1.txt (это будет один из ваших практических файлов… делайте сколько хотите)

$ gzip -r data/*.txt (заархивирует все файлы, заканчивающиеся на .txt)

Теперь вы увидите, что ваши данные заполнены файлами, оканчивающимися на .gz, что является сжатым форматом. Этот формат обычно используется при сжатии данных для отправки через HTTP. Подробнее об этом можно прочитать здесь, но это довольно скучно 💤

Код

Откройте index.js в своем редакторе.

Мы собираемся использовать модуль Zlib, поставляемый с Node, который имеет набор методов для сжатия и распаковки файлов. Мы также будем использовать модуль файловая система, чтобы позволить нам читать и записывать данные из файловой системы (потому что нам нужно читать заархивированные файлы и записывать новые, распакованные файлы. ).

Прежде всего, давайте просто разархивируем один файл, прежде чем решать, как это сделать для ВСЕХ файлов:

Мы вводим два модуля, которые нам понадобятся, а затем читаем наш первый файл, используя метод readFileSync, который проще в использовании, чем неблокирующий асинхронный метод readFile.

Если вы сейчас зарегистрируетесь fileContents, вы увидите что-то вроде этого:

ReadStream {
  _readableState:
   ReadableState {
     objectMode: false,
     highWaterMark: 65536,
     buffer: BufferList { head: null, tail: null, length: 0 },
     length: 0,
     pipes: null,
     pipesCount: 0,
     flowing: null,
     ended: false,
...etc

Однако это не похоже на содержимое вашего файла! Что есть? Так выглядят заархивированные данные?

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

Однако жаль, потому что createReadStream дает нам его по частям (ну, по одному фрагменту), и мы ничего не можем с этим поделать. 😖 И поверьте мне, другого способа сделать это на самом деле нет, потому что, как мы увидим через минуту, наш метод распаковки требует от нас использования потока.

Кстати, это отличная статья о стримах, если вы хотите узнать больше 🙌

Далее мы создаем еще один поток. Фактически два. writeStream (который позволит нам передавать разархивированные данные по частям в файл, и поток gunzip, который фактически выполнит разархивирование за нас, как только мы дадим ему поток данных.

Итак, мы передаем содержимое нашего файла так:

исходный файл → распаковать поток → новый файл

Если вы откроете file1.txt, вы увидите, что он содержит тот же текст, который вы ввели ранее.

Вся распаковка для всех файлов

Мы можем сделать то же самое, что и выше, но для каждого файла в нашем ./data каталоге. NB, возможно, стоит записать распакованные файлы в новый каталог, чтобы хранить их отдельно.

Обратите внимание, как мы отрезаем последний .gz имени файла, когда создаем имя нового файла. file1.txt.gz становится file1.txt

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

Сопоставляя имена файлов и создавая обещание для каждого из них, мы можем безопасно узнать, когда все наши файлы распакованы. Мы разрешаем каждое обещание, когда получаем событие «finish» от writeStream, говорящее о завершении записи в новый файл.

Затем вы можете продолжать делать все, что хотите, в следующем блоке .then 🙂

Снова заархивировать все это

Хорошо, вы передумали, вы хотите снова заархивировать все.

К счастью, вам нужно поменять всего несколько персонажей!

Вот и все - архивирование и разархивирование с помощью NodeJS.

Спасибо за прочтение! Надеюсь, вы чему-то научились, и не забывайте следить за мной за регулярными сообщениями о программировании 👋

x