理想如果不向現實做一點點屈服,那麼理想也將歸於塵土。
建立目錄
非同步建立目錄
path<string> | <Buffer> | <URL>
options <Object> | <integer>
- recursive <boolean> 預設值: false。
- mode <integer> Windows 上不支援。預設值: 0o777。
callback <Function>
- err <Error></Error>
// fs.mkdir(path[, mode], callback)
var fs = require('fs')
fs.mkdir('sub', function(err){
if(err) throw err
console.log('建立目錄成功')
})
執行結果:
$ node 1.js
建立目錄成功
同步建立目錄
path<string> | <Buffer> | <URL>
- options <Object> | <integer>
- recursive <boolean> 預設值: false。
mode <integer> Windows 上不支援。預設值: 0o777。
// fs.mkdirSync(path[, mode])
var fs = require('fs')
try{
fs.mkdirSync('rock')
console.log('建立目錄成功')
}catch(e){
throw e
}
執行結果:
$ node 1.js
建立目錄成功
讀取目錄
非同步讀取目錄
path<string> | <Buffer> | <URL>
options <string> | <Object>
- encoding <string> 預設值: 'utf8'。
- withFileTypes <boolean> 預設值: false。
callback <Function>
- err <Error>
- files <string[]> | <Buffer[]> | <fs.Dirent[]></Error>
注意: files 是目錄中的檔名的陣列(不包括 '.' 和 '..')
let fs = require('fs')
fs.readdir('./sub', 'utf8', (err, files) => {
if (err) console.log(err)
console.log(files)
})
執行結果:
$ node 1.js
[ '1.css', 'index.html' ]
同步讀取目錄
path <string> | <Buffer> | <URL>
options <string> | <Object>
- encoding <string> 預設值: 'utf8'。設定為 'buffer',則返回的檔名是 Buffer 物件。
- withFileTypes <boolean> 預設值: false。 設定為 true,則返回的結果將包含 fs.Dirent 物件。
返回: <string[]> | <Buffer[]> | <fs.Dirent[]></boolean>
let fs = require('fs')
try {
let result = fs.readdirSync('./sub', 'utf8')
console.log(result)
} catch (error) {
console.log(error)
}
執行結果:
$ node 1.js
[ '1.css', 'index.html' ]
遍歷目錄
var fs = require('fs')
var path = require('path')
var getFilesInDir = function (dir) {
var results = [path.resolve(dir)]
var files = fs.readdirSync(dir, 'utf8')
files.forEach(function (file) {
file = path.resolve(dir, file)
var stats = fs.statSync(file)
if (stats.isFile()) {
results.push(file)
} else if (stats.isDirectory()) {
results = results.concat(getFilesInDir(file))
}
})
return results
}
var files = getFilesInDir('./api');
console.log(files);
注意:fs.readdirSync()只會讀一層,所以需要判斷檔案型別是否目錄,如果是,則進行遞迴遍歷。
執行結果:
$ node 1.js
[ 'C:\\Users\\Administrator\\Desktop\\api',
'C:\\Users\\Administrator\\Desktop\\api\\config.1.json',
'C:\\Users\\Administrator\\Desktop\\api\\config.json',
'C:\\Users\\Administrator\\Desktop\\api\\config16.json',
'C:\\Users\\Administrator\\Desktop\\api\\integral-consumpte'
...
修改許可權
path <string> | <Buffer> | <URL>
mode <integer>
callback <Function>
- err <Error>
var fs = require('fs')
fs.chmod('1.txt', '777', function (err) {
if (err) {
console.log(err)
} else {
console.log("change done")
}
})
同步修改所有者
path <string> | <Buffer> | <URL>
mode <integer>
var fs = require('fs')
fs.chmodSync('./1.txt', '777')
訪問/許可權檢測
path<string> | <Buffer> | <URL>
mode <integer> 預設值: fs.constants.F_OK。
callback <Function>
- err <Error></Error>
const fs = require('fs')
const file = '1.txt';
// 檢查當前目錄中是否存在該檔案。
fs.access(file, fs.constants.F_OK, (err) => {
console.log(`${file} ${err ? '不存在' : '存在'}`);
});
// 檢查檔案是否可讀。
fs.access(file, fs.constants.R_OK, (err) => {
console.log(`${file} ${err ? '不可讀' : '可讀'}`);
});
// 檢查檔案是否可寫。
fs.access(file, fs.constants.W_OK, (err) => {
console.log(`${file} ${err ? '不可寫' : '可寫'}`);
});
// 檢查當前目錄中是否存在該檔案,以及該檔案是否可寫。
fs.access(file, fs.constants.F_OK | fs.constants.W_OK, (err) => {
if (err) {
console.error(
`${file} ${err.code === 'ENOENT' ? '不存在' : '只可讀'}`);
} else {
console.log(`${file} 存在,且它是可寫的`);
}
});
執行結果:
$ node 1.js
1.txt 存在
1.txt 可讀
1.txt 可寫
1.txt 存在,且它是可寫的
不建議在呼叫 fs.open()、 fs.readFile() 或 fs.writeFile() 之前使用 fs.access() 檢查檔案的可訪問性。 這樣做會引入競態條件,因為其他程式可能會在兩個呼叫之間更改檔案的狀態。 相反,應該直接開啟、讀取或寫入檔案,如果檔案無法訪問則處理引發的錯誤。
寫入(不推薦)
const fs = require('fs')
const file = '1.txt'
fs.access(file, (err) => {
if (!err) {
console.error(`${file} 已存在`)
return
}
fs.open(file, 'wx', (err, fd) => {
if (err) throw err
writeMyData(fd)
})
})
寫入(推薦)
const fs = require('fs')
fs.open('1.txt', 'wx', (err, fd) => {
if (err) {
if (err.code === 'EEXIST') {
console.error('1.txt 已存在')
return
}
throw err
}
writeMyData(fd)
})
同步訪問/許可權檢測
path<string> | <Buffer> | <URL>
mode <integer> 預設值: fs.constants.F_OK。
注意: 如果可訪問性檢查失敗,則丟擲 Error。 否則,該方法將返回 undefined。
try {
fs.accessSync('./1.txt', fs.constants.R_OK | fs.constants.W_OK)
console.log('可以讀寫')
} catch (err) {
console.error('無權訪問')
}
刪除目錄
非同步刪除目錄
path<string> | <Buffer> | <URL>
callback <Function>
- err <Error>
注意:在檔案(而不是目錄)上使用 fs.rmdir() 會導致在 Windows 上出現 ENOENT 錯誤、在 POSIX 上出現 ENOTDIR 錯誤。
var fs = require('fs')
fs.rmdir('./rock', function(err){
if(err) throw err
console.log('目錄刪除成功')
})
同步刪除目錄
path <string> | <Buffer> | <URL>
var fs = require('fs')
fs.rmdirSync('./rock')
實用場景
檔案鎖
使用獨佔標記建立鎖檔案
fs模組為所有需要開啟檔案的方法提供了一個x標記。這告訴作業系統這個檔案應該以獨佔模式開啟(O_EXCL)。當使用這個方法時,若這個檔案存在,檔案不能被開啟。
檔案資料庫
策略是不斷的追加記錄,在處理的時候不斷的覆蓋原始記錄。
var fs = require('fs')
var EventEmitter = require('events').EventEmitter
var Database = function (path) {
this.path = path
// 資料庫key/value對映表
this._records = Object.create(null)
this._writeStream = fs.createWriteStream(this.path, {
encoding: 'utf8',
flags: 'a'
})
this._load()
}
// 繼承自EventEmitter,讓它有可以監聽事件、傳遞事件的功能
Database.prototype = Object.create(EventEmitter.prototype)
Database.prototype._load = function () {
var stream = fs.createReadStream(this.path, { encoding: 'utf8' })
var database = this
var data = ''
// 當輸入流準備好時觸發
stream.on('readable', function () {
data += stream.read()
// 每一行是一組資料
var records = data.split('\n')
data = records.pop()
for (var i = 0; i < records.length; i++) {
try {
var record = JSON.parse(records[i])
if (record.value == null) {
delete database._records[record.key]
} else {
database._records[record.key] = record.value
}
} catch (e) {
database.emit('error', 'found invalid record:', records[i])
}
}
})
// 流處理完後傳送load事件給消費者
stream.on('end', function () {
database.emit('load')
})
}
let database = new Database('./sub/a.txt')
database._writeStream.write('beep')