Главная страница
Навигация по странице:

  • Пути к файлам в Node.js и модуль path

  • Получение информации о пути к файлу

  • Работа с путями к файлам

  • Чтение файлов в Node.js

  • Запись файлов в Node.js

  • Присоединение данных к файлу

  • Об использовании потоков

  • Работа с директориями в Node.js

  • Проверка существования папки

  • Чтение содержимого папки

  • Протоколы http и WebSocket Часть 9 работа с файловой системой Часть 10 стандартные модули, потоки, базы данных, node env


    Скачать 1.79 Mb.
    НазваниеПротоколы http и WebSocket Часть 9 работа с файловой системой Часть 10 стандартные модули, потоки, базы данных, node env
    Дата03.03.2019
    Размер1.79 Mb.
    Формат файлаpdf
    Имя файлаee86eb4f-db9f-48d3-8094-c76e14414678.pdf
    ТипПротокол
    #69437
    страница7 из 9
    1   2   3   4   5   6   7   8   9
    Часть 9: работа с файловой системой
    Работа с файловыми дескрипторами в Node.js
    Прежде чем вы сможете взаимодействовать с файлами, находящимися в файловой системе вашего сервера, вам необходимо получить дескриптор файла.
    Дескриптор можно получить, воспользовавшись для открытия файла асинхронным методом ​open()​ из модуля ​fs​: const fs = require('fs') fs.open('/Users/flavio/test.txt', 'r', (err, fd) => {
    //fd - это дескриптор файла
    })
    Обратите внимание на второй параметр, ​r​, использованный при вызове метода ​fs.open()​. Это — флаг, который сообщает системе о том, что файл открывают для чтения. Вот ещё некоторые флаги, которые часто используются при работе с этим и некоторыми другими методами:
    ● r+​ — открыть файл для чтения и для записи.
    ● w+​ — открыть файл для чтения и для записи, установив указатель потока в начало файла. Если файл не существует — он создаётся.
    ● a​ — открыть файл для записи, установив указатель потока в конец файла. Если файл не существует — он создаётся.
    ● a+​ — открыть файл для чтения и записи, установив указатель потока в конец файла. Если файл не существует — он создаётся.

    Файлы можно открывать и пользуясь синхронным методом ​fs.openSync()​, который, вместо того, чтобы предоставить дескриптор файла в коллбэке, возвращает его: const fs = require('fs') try { const fd = fs.openSync('/Users/flavio/test.txt', 'r')
    } catch (err) { console.error(err)
    }
    После получения дескриптора любым из вышеописанных способов вы можете производить с ним необходимые операции.
    Данные о файлах
    С каждым файлом связан набор данных о нём, исследовать эти данные можно средствами Node.js. В частности, сделать это можно, используя метод ​stat()​ из модуля ​fs​.
    Вызывают этот метод, передавая ему путь к файлу, и, после того, как Node.js получит необходимые сведения о файле, он вызовет коллбэк, переданный методу ​stat()​. Вот как это выглядит: const fs = require('fs') fs.stat('/Users/flavio/test.txt', (err, stats) => { if (err) { console.error(err) return
    }
    //сведения о файле содержатся в аргументе `stats`
    })
    В Node.js имеется возможность синхронного получения сведений о файлах. При таком подходе главный поток блокируется до получения свойств файла: const fs = require('fs') try { const stats = fs.statSync ('/Users/flavio/test.txt')
    } catch (err) { console.error(err)
    }
    Информация о файле попадёт в константу ​stats​. Что это за информация? На самом деле, соответствующий объект предоставляет нам большое количество полезных свойств и методов:

    ● Методы ​.isFile()​ и ​.isDirectory()​ позволяют, соответственно, узнать, является ли исследуемый файл обычным файлом или директорией.
    ● Метод ​.isSymbolicLink()​ позволяет узнать, является ли файл символической ссылкой.
    ● Размер файла можно узнать, воспользовавшись свойством ​.size​.
    Тут имеются и другие методы, но эти — самые употребимые. Вот как ими пользоваться: const fs = require('fs') fs.stat('/Users/flavio/test.txt', (err, stats) => { if (err) { console.error(err) return
    } stats.isFile() //true stats.isDirectory() //false stats.isSymbolicLink() //false stats.size //1024000 //= 1MB
    })
    Пути к файлам в Node.js и модуль path
    Путь к файлу — это адрес того места в файловой системе, где он расположен.
    В Linux и macOS путь может выглядеть так:
    /users/flavio/file.txt
    В Windows пути выглядят немного иначе:
    C:\users\flavio\file.txt
    На различия в форматах записи путей при использовании разных операционных систем следует обращать внимание, учитывая операционную систему, используемую для развёртывания
    Node.js-сервера.
    В Node.js есть стандартный модуль ​path​, предназначенный для работы с путями к файлам. Перед использованием этого модуля в программе его надо подключить: const path = require('path')
    Получение информации о пути к файлу
    Если у вас есть путь к файлу, то, используя возможности модуля ​path​, вы можете, в удобном для восприятия и дальнейшей обработки виде, узнать подробности об этом пути. Выглядит это так: const notes = '/users/flavio/notes.txt' path.dirname(notes) // /users/flavio path.basename(notes) // notes.txt
    path.extname(notes) // .txt
    Здесь, в строке ​notes​, хранится путь к файлу. Для разбора пути использованы следующие методы модуля ​path​:
    ● dirname()​ — возвращает родительскую директорию файла.
    ● basename()​ — возвращает имя файла.
    ● extname()​ — возвращает расширение файла.
    Узнать имя файла без расширения можно, вызвав метод ​.basename()​ и передав ему второй аргумент, представляющий расширение: path.basename(notes, path.extname(notes)) //notes
    Работа с путями к файлам
    Несколько частей пути можно объединить, используя метод ​path.join()​: const name = 'flavio' path.join('/', 'users', name, 'notes.txt') //'/users/flavio/notes.txt'
    Найти абсолютный путь к файлу на основе относительного пути к нему можно с использованием метода ​path.resolve()​: path.resolve('flavio.txt')
    //'/Users/flavio/flavio.txt' при запуске из моей домашней папки
    В данном случае Node.js просто добавляет ​/flavio.txt​ к пути, ведущем к текущей рабочей директории. Если при вызове этого метода передать ещё один параметр, представляющий путь к папке, метод использует его в качестве базы для определения абсолютного пути: path.resolve('tmp', 'flavio.txt')
    // '/Users/flavio/tmp/flavio.txt' при запуске из моей домашней папки
    Если путь, переданный в качестве первого параметра, начинается с косой черты — это означает, что он представляет собой абсолютный путь. path.resolve('/etc', 'flavio.txt')
    // '/etc/flavio.txt'
    Вот ещё один полезный метод — ​path.normalize()​. Он позволяет найти реальный путь к файлу, используя путь, в котором содержатся спецификаторы относительного пути вроде точки (​.​), двух точек
    (​..​), или двух косых черт: path.normalize('/users/flavio/..//test.txt')
    // /users/test.txt
    Методы ​resolve()​ и ​normalize()​ не проверяют существование директории. Они просто находят путь, основываясь на переданным им данным.

    Чтение файлов в Node.js
    Самый простой способ чтения файлов в Node.js заключается в использовании метода ​fs.readFile() с передачей ему пути к файлу и коллбэка, который будет вызван с передачей ему данных файла (или объекта ошибки): fs.readFile('/Users/flavio/test.txt', (err, data) => { if (err) { console.error(err) return
    } console.log(data)
    })
    Если надо, можно воспользоваться синхронной версией этого метода — ​fs.readFileSync()​: const fs = require('fs') try { const data = fs.readFileSync('/Users/flavio/test.txt') console.log(data)
    } catch (err) { console.error(err)
    }
    По умолчанию при чтении файлов используется кодировка ​utf8​, но кодировку можно задать и самостоятельно, передав методу соответствующий параметр.
    Методы ​fs.readFile()​ и ​fs.readFileSync()​ считывают в память всё содержимое файла. Это означает, что работа с большими файлами с применением этих методов серьёзно отразится на потреблении памяти вашим приложением и окажет влияние на его производительность. Если с такими файлами нужно работать, лучше всего воспользоваться потоками.
    Запись файлов в Node.js
    В Node.js легче всего записывать файлы с использованием метода ​fs.writeFile()​: const fs = require('fs') const content = 'Some content!' fs.writeFile('/Users/flavio/test.txt', content, (err) => { if (err) { console.error(err) return

    }
    //файл записан успешно
    })
    Есть и синхронная версия того же метода — ​fs.writeFileSync()​: const fs = require('fs') const content = 'Some content!' try { const data = fs.writeFileSync('/Users/flavio/test.txt', content)
    //файл записан успешно
    } catch (err) { console.error(err)
    }
    Эти методы, по умолчанию, заменяют содержимое существующих файлов. Изменить их стандартное поведение можно, воспользовавшись соответствующим флагом: fs.writeFile('/Users/flavio/test.txt', content, { flag: 'a+' }, (err) => {})
    Тут могут использоваться флаги, которые мы уже перечисляли в разделе, посвящённом дескрипторам.
    Подробности о флагах можно узнать ​
    здесь​
    Присоединение данных к файлу
    Метод ​fs.appendFile()​ (и его синхронную версию — ​fs.appendFileSync()​) удобно использовать для присоединения данных к концу файла: const content = 'Some content!' fs.appendFile('file.log', content, (err) => { if (err) { console.error(err) return
    }
    //готово!
    })
    Об использовании потоков
    Выше мы описывали методы, которые, выполняя запись в файл, пишут в него весь объём переданных им данных, после чего, если используются их синхронные версии, возвращают управление программе, а если применяются асинхронные версии — вызывают коллбэки. Если вас такое состояние дел не устраивает — лучше будет воспользоваться потоками.

    Работа с директориями в Node.js
    Модуль ​fs​ предоставляет в распоряжение разработчика много удобных методов, которые можно использовать для работы с директориями.
    Проверка существования папки
    Для того чтобы проверить, существует ли директория и может ли Node.js получить к ней доступ, учитывая разрешения, можно использовать метод ​fs.access()​.
    Создание новой папки
    Для того чтобы создавать новые папки, можно воспользоваться методами ​fs.mkdir()​ и fs.mkdirSync()​: const fs = require('fs') const folderName = '/Users/flavio/test' try { if (!fs.existsSync(dir)){ fs.mkdirSync(dir)
    }
    } catch (err) { console.error(err)
    }
    Чтение содержимого папки
    Для того чтобы прочесть содержимое папки, можно воспользоваться методами ​fs.readdir()​ и fs.readdirSync()​. В этом примере осуществляется чтение содержимого папки — то есть — сведений о том, какие файлы и поддиректории в ней имеются, и возврат их относительных путей: const fs = require('fs') const path = require('path') const folderPath = '/Users/flavio' fs.readdirSync(folderPath)
    Вот так можно получить полный путь к файлу: fs.readdirSync(folderPath).map(fileName => { return path.join(folderPath, fileName)
    }
    Результаты можно отфильтровать для того, чтобы получить только файлы и исключить из вывода директории: const isFile = fileName => { return fs.lstatSync(fileName).isFile()

    } fs.readdirSync(folderPath).map(fileName => { return path.join(folderPath, fileName)).filter(isFile)
    }
    Переименование папки
    Для переименования папки можно воспользоваться методами ​fs.rename()​ и ​fs.renameSync()​.
    Первый параметр — это текущий путь к папке, второй — новый: const fs = require('fs') fs.rename('/Users/flavio', '/Users/roger', (err) => { if (err) { console.error(err) return
    }
    //готово
    })
    Переименовать папку можно и с помощью синхронного метода ​fs.renameSync()​: const fs = require('fs') try { fs.renameSync('/Users/flavio', '/Users/roger')
    } catch (err) { console.error(err)
    }
    Удаление папки
    Для того чтобы удалить папку, можно воспользоваться методами ​fs.rmdir()​ или ​fs.rmdirSync()​.
    Надо отметить, что удаление папки, в которой что-то есть, задача несколько более сложная, чем удаление пустой папки. Если вам нужно удалять такие папки, воспользуйтесь пакетом ​
    fs-extra​
    , который весьма популярен и хорошо поддерживается. Он представляет собой замену модуля ​fs​, расширяющую его возможности.
    Метод ​remove()​ из пакета ​fs-extra​ умеет удалять папки, в которых уже что-то есть.
    Установить этот модуль можно так: npm install fs-extra
    Вот пример его использования: const fs = require('fs-extra')
    const folder = '/Users/flavio' fs.remove(folder, err => { console.error(err)
    })
    Его методами можно пользоваться в виде промисов: fs.remove(folder).then(() => {
    //готово
    }).catch(err => { console.error(err)
    })
    Допустимо и применение конструкции async/await: async function removeFolder(folder) { try { await fs.remove(folder)
    //готово
    } catch (err) { console.error(err)
    }
    } const folder = '/Users/flavio' removeFolder(folder)
    Модуль fs
    Выше мы уже сталкивались с некоторыми методами модуля ​fs​, применяемыми при работе с файловой системой. На самом деле, он содержит ещё много полезного. Напомним, что он не нуждается в установке, для того, чтобы воспользоваться им в программе, его достаточно подключить: const fs = require('fs')
    После этого у вас будет доступ к его методам, среди которых отметим следующие, некоторые из которых вам уже знакомы:
    ● fs.access()​: проверяет существование файла и возможность доступа к нему с учётом разрешений.
    ● fs.appendFile()​: присоединяет данные к файлу. Если файл не существует — он будет создан.
    ● fs.chmod()​: изменяет разрешения для заданного файла. Похожие методы: ​fs.lchmod()​, fs.fchmod()​.

    ● fs.chown()​: изменяет владельца и группу для заданного файла. Похожие методы: fs.fchown()​, ​fs.lchown()​.
    ● fs.close()​: закрывает дескриптор файла.
    ● fs.copyFile()​: копирует файл.
    ● fs.createReadStream()​: создаёт поток чтения файла.
    ● fs.createWriteStream()​: создаёт поток записи файла.
    ● fs.link()​: создаёт новую жёсткую ссылку на файл.
    ● fs.mkdir()​: создаёт новую директорию.
    ● fs.mkdtemp()​: создаёт временную директорию.
    ● fs.open()​: открывает файл.
    ● fs.readdir()​: читает содержимое директории.
    ● fs.readFile()​: считывает содержимое файла. Похожий метод: ​fs.read()​.
    ● fs.readlink()​: считывает значение символической ссылки.
    ● fs.realpath()​: разрешает относительный путь к файлу, построенный с использованием символов ​. ​и​ ..​, в полный путь.
    ● fs.rename()​: переименовывает файл или папку.
    ● fs.rmdir()​: удаляет папку.
    ● fs.stat()​: возвращает сведения о файле. Похожие методы: ​fs.fstat()​, ​fs.lstat()​.
    ● fs.symlink()​: создаёт новую символическую ссылку на файл.
    ● fs.truncate()​: обрезает файл до заданной длины. Похожий метод: ​fs.ftruncate()​.
    ● fs.unlink()​: удаляет файл или символическую ссылку.
    ● fs.unwatchFile()​: отключает наблюдение за изменениями файла.
    ● fs.utimes()​: изменяет временную отметку файла. Похожий метод: ​fs.futimes()​.
    ● fs.watchFile()​: включает наблюдение за изменениями файла. Похожий метод: ​fs.watch()​.
    ● fs.writeFile()​: записывает данные в файл. Похожий метод: ​fs.write()​.
    Интересной особенностью модуля ​fs​ является тот факт, что все его методы, по умолчанию, являются асинхронными, но существуют и их синхронные версии, имена которых получаются путём добавления слова ​Sync​ к именам асинхронных методов.
    Например:
    ● fs.rename()
    ● fs.renameSync()
    ● fs.write()
    ● fs.writeSync()
    Использование синхронных методов серьёзно влияет на то, как работает программа.
    В Node.js 10 имеется экспериментальная поддержка этих ​
    API​
    , основанных на промисах.
    Исследуем метод ​fs.rename()​. Вот асинхронная версия этого метода, использующая коллбэки: const fs = require('fs') fs.rename('before.json', 'after.json', (err) => { if (err) { return console.error(err)
    }
    //готово

    })
    При использовании его синхронной версии для обработки ошибок используется конструкция try/catch​: const fs = require('fs') try { fs.renameSync('before.json', 'after.json')
    //готово
    } catch (err) { console.error(err)
    }
    Основное различие между этими вариантами использования данного метода заключается в том, что во втором случае выполнение скрипта будет заблокировано до завершения файловой операции.
    Модуль path
    Модуль path, о некоторых возможностях которого мы тоже уже говорили, содержит множество полезных инструментов, позволяющих взаимодействовать с файловой системой. Как уже было сказано, устанавливать его не нужно, так как он является частью Node.js. Для того чтобы пользоваться им, его достаточно подключить: const path = require('path')
    Свойство ​path.sep​ этого модуля предоставляет символ, использующийся для разделения сегментов пути (​\​ в Windows и ​/​ в Linux и macOS), а свойство ​path.delimiter​ даёт символ, используемый для отделения друг от друга нескольких путей (​;​ в Windows и ​:​ в Linux и macOS).
    Рассмотрим и проиллюстрируем примерами некоторые методы модуля ​path​.
    path.basename()
    Возвращает последний фрагмент пути. Передав второй параметр этому методу можно убрать расширение файла. require('path').basename('/test/something') //something require('path').basename('/test/something.txt') //something.txt require('path').basename('/test/something.txt', '.txt') //something
    path.dirname()
    Возвращает ту часть пути, которая представляет имя директории: require('path').dirname('/test/something') // /test require('path').dirname('/test/something/file.txt') // /test/something
    path.extname()
    Возвращает ту часть пути, которая представляет расширение файла: require('path').dirname('/test/something') // ''
    require('path').dirname('/test/something/file.txt') // '.txt'
    path.isAbsolute()
    Возвращает истинное значение если путь является абсолютным: require('path').isAbsolute('/test/something') // true require('path').isAbsolute('./test/something') // false
    path.join()
    Соединяет несколько частей пути: const name = 'flavio' require('path').join('/', 'users', name, 'notes.txt')
    //'/users/flavio/notes.txt'
    path.normalize()
    Пытается выяснить реальный путь на основе пути, который содержит символы, использующиеся при построении относительных путей вроде ​.​, ​..​ и ​//​: require('path').normalize('/users/flavio/..//test.txt') ///users/test.txt
    path.parse()
    Преобразует путь в объект, свойства которого представляют отдельные части пути:
    ● root​: корневая директория.
    ● dir​: путь к файлу, начиная от корневой директории
    ● base​: имя файла и расширение.
    ● name​: имя файла.
    ● ext​: расширение файла.
    Вот пример использования этого метода: require('path').parse('/users/test.txt')
    В результате его работы получается такой объект:
    { root: '/', dir: '/users', base: 'test.txt', ext: '.txt', name: 'test'
    }
    path.relative()
    Принимает, в качестве аргументов, 2 пути. Возвращает относительный путь из первого пути ко второму, основываясь на текущей рабочей директории: require('path').relative('/Users/flavio', '/Users/flavio/test.txt')
    //'test.txt'
    require('path').relative('/Users/flavio', '/Users/flavio/something/test.txt')
    //'something/test.txt'
    path.resolve()
    Находит абсолютный путь на основе переданного ему относительного пути: path.resolve('flavio.txt')
    //'/Users/flavio/flavio.txt' при запуске из моей домашней папки.
    1   2   3   4   5   6   7   8   9


    написать администратору сайта