آموزش Node.js: کار با فایل توسط ماژول fs – بخش نهم


در این بخش از سری مقالات آموزش Node.js به بررسی روش کار با فایلها با استفاده از ماژول fs می پردازیم. برای مطالعه بخش قبلی این مجموعه مطلب آموزشی، میتوانید به لینک زیر مراجعه کنید:
پیش از آن که بتوانید با فایلهایی که در فایلسیستم شما قرار دارند، کار کنید باید یک توصیفگر فایل داشته باشید. «توصیفگر فایل» (File Descriptor) چیزی است که در زمان باز کردن فایل با متد ()OPEN در ماژول fs به دست میآید:
1const fs = require('fs')
2
3fs.open('/Users/flavio/test.txt'،
4 'r'،(err، fd) => { //fd is our file descriptor
5})
دقت کنید که ما از r به عنوان پارامتر دوم برای فراخوانی ()fs.open استفاده میکنیم. معنی این فلگ آن است که فایل برای خواندن باز شده است. فلگهای دیگر که به طور عمده استفاده میشوند، شامل موارد فهرست زیر هستند:
- +r فایل را برای خواندن و نوشتن باز میکند.
- +w فایل را برای خواندن و نوشتن باز میکند، استریم را در ابتدای فایل قرار میدهد. در صورتی که فایل موجود نباشد، ساخته میشود.
- a فایل را برای نوشتن باز میکند، استریم را در انتهای فایل قرار میدهد. در صورتی که فایل موجود نباشد، آن را میسازد.
- +a فایل را برای خواندن و نوشتن باز میکند، استریم را در انتهای فایل قرار میدهد. در صورتی که فایل موجود نباشد، آن را میسازد.
همچنین میتوان فایل را با استفاده از متد fs.openSync باز کرد که به جای ارائه شیء توصیفگر فایل در یک callback آن را به صورت زیر بازگشت میدهد:
1const fs = require('fs')
2
3try {
4 const fd = fs.openSync('/Users/flavio/test.txt'،
5 'r')
6} catch (err) {
7 console.error(err)
8}
زمانی که توصیفگرِ فایل خود را به هر طریقی که تشخیص میدهید، به دست آوردید، میتوانید همه عملیاتی که نیاز دارد مانند ()fs.open و بسیاری عملیات دیگر را که با فایلسیستم تعامل دارند اجرا کنید.
آمار فایل در Node.js
هر فایل مجموعهای جزییات دارد که میتوان با استفاده از Node.js آنها را بازبینی کرد.
به طور خاص استفاده از متد ()start که از سوی ماژول fs ارائه شده به این منظور مفید است. میتوان مسیر فایل را به این متد ارسال کرد و زمانی که Node.js جزییات فایل را دریافت کرد، تابع callback را با 2 پارامتر فراخوانی میکند. این پارامترها شامل یک پیام خطا و آمار فایل است:
1const fs = require('fs') fs.stat('/Users/flavio/test.txt'،(err، stats) => {
2 if (err) {
3 console.error(err) return
4 } //we have access to the file stats in `stats`
5})
Node.js همچنین یک متد sync عرضه میکند که نخ را تا زمانی که آمار فایل آماده نشده است، مسدود میکند:
1const fs = require('fs') try {
2 const stats = fs.stat('/Users/flavio/test.txt')
3} catch (err) {
4 console.error(err)
5}
این اطلاعات در متغیر stats ذخیره میشوند. بدین ترتیب میتوانیم اطلاعات زیادی در مورد فایل به دست آوریم که برخی از آنها در ادامه فهرست شدهاند:
- با استفاده از ()stats.isFile و ()stats.isDirectory بررسی میکنیم آیا فایل واقعاً یک فایل است یا یک دایرکتوری است.
- اگر فایل یک «پیوند نمادین» (symbolic link) باشد با استفاده از ()stats.isSymbolicLink آن را بررسی میکنیم.
- با استفاده stats.size اندازه فایل را بر حسب بایت بررسی میکنیم.
متدهای پیشرفته دیگری نیز وجود دارند، اما عمده مواردی که به صورت روزمره استفاده میشوند، به صورت زیر است:
1const fs = require('fs') fs.stat('/Users/flavio/test.txt', (err, stats) => {
2 if (err) {
3 console.error(err) return
4 }
5 stats.isFile() //true
6 stats.isDirectory() //false
7 stats.isSymbolicLink() //false
8 stats.size //1024000 //= 1MB
9})
مسیرهای فایل در Node.js
هر فایل در سیستم یک مسیر دارد. روی لینوکس و macOS مسیر به صورت زیر است:
/users/flavio/file.txt
روی رایانههای ویندوزی مسیر متفاوت است و ساختاری مانند زیر دارد:
C:\users\flavio\file.txt
بدین ترتیب زمانی که از مسیرها در اپلیکیشن خود استفاده میکنید باید به این تفاوت توجه داشته باشید و آن را در نظر بگیرید. با استفاده از دستور زیر این ماژول را در فایلهای خود بگنجانید:
1const path = require('path')
بدین ترتیب میتوانید از متدهای آن استفاده کنید.
دریافت اطلاعات از یک مسیر
با فرض وجود یک مسیر برای فایل، میتوان اطلاعاتی را در مورد آن با استفاده از این متدها استخراج کرد:
- Dirname – پوشه والد فایل را دریافت میکند.
- Basename – بخش نام فایل را از مسیر فایل دریافت میکند.
- Extname – بخش نام پسوند فایل را استخراج میکند.
به مثال زیر توجه کنید:
1const notes = '/users/flavio/notes.txt'
2path.dirname(notes) // /users/flaviopath.basename(notes) // notes.txtpath.extname(notes) // .txt
نام فایل را میتوان بدون پسوند و از طریق تعیین آرگومان دوم به صورت basename به دست آورد:
1path.basename(notes، path.extname(notes)) //notes
کار با مسیرها
میتوان دو یا چند بخش از یک مسیر را با استفاده از متد ()path.join با هم ترکیب کرد:
1const name = 'flavio'path.join('/', 'users', name, 'notes.txt') //'/users/flavio/notes.txt'
میتوان مسیر مطلق یک فایل را از روی مسیر نسبی آن با استفاده از متد ()path.resolve محاسبه کرد:
1path.resolve('flavio.txt') //'/Users/flavio/flavio.txt' if run from my home folder
در این حالت Node.js به سادگی flavio.txt/ را به دایرکتوری کاری جاری پیوست میکند. اگر در پارامتر دوم نام یک پوشه را ذکر کنید، resolve از آرگومان نخست به عنوان مبنایی برای دوم استفاده میکند:
1path.resolve('tmp'، 'flavio.txt')// '/Users/flavio/tmp/flavio.txt' if run from my home folder
اگر پارامتر اول با یک اسلش (/) آغاز شود، این بدان معنی است که یک مسیر مطلق است:
1path.resolve('/etc'، 'flavio.txt')// '/etc/flavio.txt'
یک تابع مفید دیگر ()path.normalize است که تلاش میکند مسیر واقعی را از روی توصیفکنندههای نسبی مانند . یا .. یا اسلشهای دوبل (//) محاسبه کند:
1path.normalize('/users/flavio/..//test.txt') // /users/test.txt
اما resolve و normalize بررسی نمیکنند که آیا مسیر وجود دارد یا نه. آنها صرفاً مسیر را بر مبنای اطلاعاتی که شما ارائه میکنید محاسبه میکنند.
خواندن فایلها با Node.js
سادهترین روش برای خواندن یک فایل در Node.js استفاده از متد ()fs.readFile است که مسیر نخست و یک تابع callback به آن ارسال میشود و با دادههای فایل (و خطا) فراخوانی میشود:
1const fs = require('fs')
2fs.readFile('/Users/flavio/test.txt', (err, data) => {
3 if (err) {
4 console.error(err) return
5 }
6 console.log(data)
7})
به طور جایگزین میتوانید از نسخه ناهمگام آن یعنی ()fs.readFileSync نیز استفاده کنید:
1const fs = require('fs')
2try {
3 const data = fs.readFileSync('/Users/flavio/test.txt') console.log(data)
4} catch (err) {
5 console.error(err)
6}
انکودینگ پیشفرض در زمان خواندن فایل utf8 است، اما میتوان انکودینگ خاصی را با استفاده از پارامتر دوم تعیین کرد. هر دو متد ()fs.readFile و ()fs.readFileSync پیش از بازگشت دادن دادهها، محتوای کامل فایل را در حافظه میخوانند.
این بدان معنی است که فایلها میتوانند تأثیر زیادی روی مصرف حافظه و سرعت اجرای برنامه داشته باشند. در این حالت، گزینه بهتر میتواند خواندن محتوای فایل با استفاده از «استریم» (Stream) باشد.
نوشتن فایلها در Node.js
آسانترین روش برای نوشتن فایلها در Node.js استفاده از API به نام ()fs.writeFile است. به مثال زیر توجه کنید:
1const fs = require('fs')
2const content = 'Some content!'
3fs.writeFile('/Users/flavio/test.txt', content, (err) => {
4 if (err) {
5 console.error(err) return
6 } //file written successfully
7})
به طور جایگزین میتوانید از نسخه ناهمگام آن یعنی ()fs.writeFileSync نیز استفاده کنید:
1const fs = require('fs')
2const content = 'Some content!'
3try {
4 const data = fs.writeFileSync('/Users/flavio/test.txt', content) //file written successfully
5} catch (err) {
6 console.error(err)
7}
این API به صورت پیشفرض، در صورت وجود داشتن فایل، محتوای آن را عوض میکند. شما میتوانید با استفاده از فلگهای زیر این رفتار را عوض کنید:
1fs.writeFile('/Users/flavio/test.txt'، content، { flag: 'a+' }، (err) => {})
فلگهایی که میتوان استفاده کرد به شرح زیر هستند:
- +r فایل را برای خواندن و نوشتن باز میکند.
- +w فایل را برای خواندن و نوشتن باز میکند و استریم را در ابتدای فایل قرار میدهد. در صورتی که فایل وجود نداشته باشد، آن را ایجاد میکند.
- a فایل را برای خواندن و نوشتن باز میکند و استریم را در انتهای فایل قرار میدهد. در صورتی که فایل وجود نداشته باشد، آن را ایجاد میکند.
- +a فایل را برای خواندن و نوشتن باز میکند و استریم را در انتهای فایل قرا میدهد. در صورتی که فایل وجود نداشته باشد، آن را ایجاد میکند.
الحاق محتوایی به فایل
یک متد کارآمد برای الحاق محتوا به انتهای یک فایل ()fs.appendFile و متد همتای آن ()fs.appendFileSync است:
1const content = 'Some content!'
2fs.appendFile('file.log', content, (err) => {
3 if (err) {
4 console.error(err) return
5 } //done!
6})
استفاده از استریمها
همه این متدها محتوای کامل فایل را پیش از بازگشت دادن کنترل به برنامه مینویسند (در نسخه sync این بدان معنی است که callback اجرا میشود). در این حالت یک گزینه بهتر، نوشتن محتوای فایل با استفاده از استریم است.
کار با پوشهها در Node.js
ماژول مرکزی fs در Node.js متدهای کارآمد زیادی ارائه میکند که میتوان برای کار با پوشهها مورد استفاده قرار داد.
بررسی وجود یک پوشه
با استفاده از ()fs.access میتوان بررسی کرد که آیا یک پوشه وجود دارد یا نه و Node.js میتواند با مجوزهای خود به آن دسترسی یابد.
ایجاد یک پوشه جدید
از ()fs.mkdir یا ()fs.mkdirSync برای ایجاد یک پوشه جدید استفاده کنید:
1const fs = require('fs')
2const folderName = '/Users/flavio/test'
3try {
4 if (!fs.existsSync(dir)) {
5 fs.mkdirSync(dir)
6 }
7} catch (err) {
8 console.error(err)
9}
خواندن محتوای یک پوشه
از ()fs.readdir یا ()fs.readdirSync برای خواندن محتوای یک دایرکتوری استفاده کنید. این قطعه کد محتوای یک پوشه را میخواند. این مسیر شامل فایلها و زیرپوشهها نیز میشود و مسیر نسبی آنها را بازگشت میدهد:
1const fs = require('fs')const path = require('path')
2const folderPath = '/Users/flavio'
3fs.readdirSync(folderPath)
مسیر کامل را میتوان به صورت زیر به دست آورد:
1fs.readdirSync(folderPath).map(fileName => { return path.join(folderPath، fileName)}
همچنین میتوان نتایج را طوری فیلتر کرد که تنها فایلها بازگشت یابند و پوشهها حذف شوند:
1const isFile = fileName => {
2 return fs.lstatSync(fileName).isFile()
3}
4fs.readdirSync(folderPath).map(fileName => {
5 return path.join(folderPath, fileName)).filter(isFile)
6}
تغییر دادن نام یک پوشه
با استفاده از متدهای ()fs.rename یا ()fs.renameSync میتوان نام یک پوشه را تغییر داد. پارامتر اول مسیر جاری و پارامتر دوم مسیر جدید است:
1const fs = require('fs')
2fs.rename('/Users/flavio', '/Users/roger', (err) => {
3 if (err) {
4 console.error(err) return
5 } //done
6})
متد ()fs.renameSync نسخه ناهمگام است:
1const fs = require('fs')
2
3try {
4 fs.renameSync('/Users/flavio'،
5 '/Users/roger')
6} catch (err) {
7 console.error(err)
8}
حذف کردن یک پوشه
با استفاده از ()fs.rmdir یا ()fs.rmdirSync میتوان یک پوشه را حذف کرد. حذف کردن یک پوشه که محتوایی دارد ممکن است پیچیدهتر از چیزی باشد که نیاز دارید.
در این حالت پیشنهاد میکنیم ماژول fs-extra را نصب کنید که بسیار محبوب است و به خوبی نگهداری میشود. این ماژول یک جایگزین قطعی برای ماژول fs است که بر مبنای آن ساخته شده و قابلیتهای بیشتری ارائه میکند.
در این حالت متد ()remove میتواند برای حذف فایل استفاده شود. ابتدا آن را با استفاده از دستور زیر نصب کنید:
npm install fs-extra
استفاده از آن نیز به صورت زیر است:
1const fs = require('fs-extra')
2const folder = '/Users/flavio'
3fs.remove(folder, err => {
4 console.error(err)
5})
همچنین میتوان با استفاده از Promise-ها از آن استفاده کرد:
1fs.remove(folder).then(() => { //done
2}).catch(err => {
3 console.error(err)
4})
یا میتوان از async/await استفاده کرد:
1async function removeFolder(folder) {
2 try {
3 await fs.remove(folder) //done
4 } catch (err) {
5 console.error(err)
6 }
7}
8
9const folder = '/Users/flavio'
10removeFolder(folder)
بدین ترتیب به پایان این نوشته با موضوع روش کار با فایل در Node.js میرسیم. Node.js ماژولهای مفید زیاد دیگری نیز دارد که در بخشهای بعدی این سری مقالات به بررسی آنها نیز خواهیم پرداخت. برای مطالعه بخش بعدی به لینک زیر مراجعه کنید:
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای JavaScript (جاوا اسکریپت)
- Node.js چیست؟ — به زبان ساده
- مجموعه آموزشهای برنامهنویسی
- آموزش Node.js: برنامه نویسی ناهمگام و Callback — بخش هفتم
- چگونه کد Node.js را با استفاده از Bytenode کامپایل کنیم؟ — راهنمای گام به گام
==
سلام. من به این طریق یه پوشه داخل یوزر هاستم ساختم. اما سازنده پوشه رو زده root و از طریق یوزر امکان دسترسی و حذف و … نداره.