jbd
Version:
jBD Framework's Core
340 lines (301 loc) • 8.63 kB
JavaScript
/**
* ==========================================
* Name: FS
* Author: Buddy-Deus
* CreTime: 2016-02-16
* Description: 基础文件操作
* Log
* 2016-02-16 初始化
* ==========================================
*/
jBD.define(function (module, exports, require) {
"use strict";
let API;
const fs = require("fs"),
path = require("path"),
txtFileType = [".txt", ".json", ".ini", ".js", ".css", ".html", ".md"],
encodeType = ["ascii", "utf8", "utf16le"];
const fmtPath = value => value.trim().replace(/\\/g, "/"),
isTXT = value => jBD.has(path.extname(value).toLowerCase(), txtFileType),
listDir = (src, callback) => {
let list = fs.readdirSync(src),
state = true,
count = 0;
for (let i = 0, o; i < list.length; i++) {
if (!state) return;
count++;
o = path.join(src, list[i]);
if (callback(list[i], o, fs.statSync(o)) === false) break;
}
return count;
},
operFile_TXT = (src, dest, callback, move, encoding, sync) => {
if (sync) {
try {
fs.writeFileSync(dest, fs.readFileSync(src, encoding), encoding);
if (callback) callback("end", src, dest);
if (move) fs.unlinkSync(src);
}
catch (e) {
if (callback) callback("error", src, dest, e);
}
}
else {
fs.writeFile(dest, fs.readFileSync(src, encoding), encoding, err => {
if (callback) callback(err ? "error" : "end", src, dest, err);
if (!err && move) fs.unlinkSync(src);
});
}
},
operFile_Stream = (src, dest, callback, move) => {
let rs = fs.createReadStream(src),
ws = fs.createWriteStream(dest);
ws.on("end", () => {
ws.end();
if (callback) callback("end", src, dest);
if (move) fs.unlinkSync(src);
});
if (!callback) rs.pipe(ws);
else {
rs.pipe(require('stream').Transform({
transform: function (buf, enc, next) {
if (callback) callback("data", src, dest);
next(null, buf);
}
})).pipe(ws);
}
},
operFile = (src, dest, opt, callback) => {
API.Make(dest, true);
if (!opt.stream && isTXT(src)) operFile_TXT(src, dest, callback, opt.move, opt.encoding, opt.sync);
else operFile_Stream(src, dest, callback, opt.move);
},
operDir = (src, dest, opt, callback) => {
opt.count = listDir(src, (f, p, o) => {
if (o.isDirectory()) operDir(path.join(src, f), path.join(dest, f), opt, callback);
else operFile(path.join(src, f), path.join(dest, f), {
sync: true,
stream: opt.stream,
encoding: opt.encoding,
move: opt.move
}, callback)
});
if (opt.empty && opt.count == 0) API.Make(dest);
};
API = {
/**
* 列表目录
* 当 deep=true && show=1 时,列出此目录下所有文件(包含子目录)
*
* @param {string} src
* @param {object|boolean} opt
* @param {boolean} [opt.deep=false] 是否搜索子目录
* @param {boolean|number} [opt.show=0] 过滤方式
* @param {function} callback
* @returns {Array}
*/
List: (src, opt = {}, callback = opt) => {
let result = [],
{
deep,
show
} = opt;
switch (typeof (opt)) {
case "boolean":
deep = opt;
break;
case "number":
case "string":
show = opt;
break;
}
deep = deep === true;
switch (String(show)) {
default:
show = 0;
break;
case "1":
case "file":
case "true":
show = 1;
break;
case "2":
case "dir":
case "false":
show = 2;
break;
}
if (!jBD.isFunction(callback)) callback = null;
if (!fs.existsSync(src)) return result;
listDir(src, (f, p, o, l) => {
o = {name: f, path: p, state: o, dir: o.isDirectory()};
l = result.length;
result.push(o);
if (o.dir) {
if (deep) {
Array.prototype.push(
show == 1 ? result : (o.child = []),
API.List(
o.path,
{
deep: true,
show: show
},
callback)
);
}
else if (show == 1) result.pop();
}
else if (show == 2) result.pop();
if (l == result.length) return;
if (callback && callback(o.name, o.path, o.dir, o.state) === false) return false;
});
return result;
},
/**
* 创建目录
*
* @param {string} src
* @param {boolean} [file=false]
* @returns {string}
*/
Make: (src, file = false) => {
src = fmtPath(src);
file = file === true;
let dest = src;
if (fs.existsSync(dest)) return dest;
for (let i = 0, c = file ? 1 : 0, l = dest.split("/"), o = ""; i < l.length - c; i++) {
if (i == 0) o = l[0] || "/";
else if (l[i] && !fs.existsSync(o = path.join(o, l[i]))) fs.mkdirSync(o);
dest = o;
}
return dest;
},
/**
* 删除目录
*
* @param {string} dest
* @param {boolean} [self=true] 是否删除自身
* @returns {boolean}
*/
Remove: (dest, self = true) => {
dest = fmtPath(dest);
self = self !== false;
if (!fs.existsSync(dest)) return false;
if (fs.statSync(dest).isFile()) fs.unlinkSync(dest);
else {
listDir(dest, (f, p, o) => {
if (o.isDirectory()) API.Remove(p, true);
else fs.unlinkSync(p);
});
if (self) fs.rmdirSync(dest);
}
return true;
},
/**
* 操作目录/文件 (移动/复制)
*
* @param {string} src
* @param {string} dest
* @param {object} [opt]
* @param {boolean} [opt.stream=false] 是否启用文件流,否则作为自动识别
* @param {boolean} [opt.sync=false] 是否异步方式
* @param {string} [opt.encoding=utf8] 编码格式
* @param {boolean} [opt.empty=true] 是否创建空目录
* @param {boolean} [opt.move=false] 是否移动
* @param {function} [callback]
*/
Oper: (src, dest, opt = {}, callback = opt) => {
if (!fs.existsSync(src)) return;
let {sync, stream, encoding, empty, move} = opt;
switch (typeof(opt)) {
case "string":
encoding = opt;
break;
case "boolean":
move = opt;
break;
}
sync = sync === true;
stream = stream === false;
if (!jBD.has(encoding, encodeType)) encoding = encodeType[0];
empty = empty !== false;
move = move === true;
opt = {sync, stream, encoding, empty, move};
callback = ((func, rm) => {
return (tag, src, dest) => {
if (func) func(tag, src, dest);
if (tag == "end" && rm) rm(src);
};
})(jBD.isFunction(callback) ? callback : null, opt.move ? API.Remove : null);
if (fs.statSync(src).isDirectory()) operDir(src, dest, opt, callback);
else operFile(src, dest, opt, callback);
},
/**
* 打开文件
*
* @param {string} src
* @param {object} [opt]
* @param {string} [opt.encoding=utf8] 编码方式
* @param {boolean} [opt.obj=true] 是否建立对象
* @returns {buffer|object|string}
*/
Load: (src, opt = {}) => {
if (!fs.existsSync(src)) return null;
let txt = isTXT(src),
{
encoding,
obj
} = opt,
result;
switch (typeof(opt)) {
case "boolean":
obj = opt;
break;
case "string":
encoding = opt;
break;
}
obj = obj !== false;
encoding = txt ? (jBD.has(encoding, encodeType) ? encoding : "utf8") : null;
result = fs.readFileSync(src, encoding);
if (txt) {
result = result.toString();
if (obj) result = jBD.Conver.toJSON(result);
}
return result;
},
/**
* 保存文件
*
* @param {string} dest
* @param {buffer|Uint8Array|object|string} [opt]
* @param {buffer|Uint8Array|object|string} [opt.data='']
* @param {boolean} [opt.write=true] 覆盖全部内容
* @param {string} [opt.encoding=utf8]
* @constructor
*/
Save: (dest, opt = {}) => {
let {data, write, encoding} = opt;
switch (typeof(opt)) {
case "object":
if (opt instanceof Buffer) data = opt;
else if (opt instanceof Uint8Array) data = opt;
break;
case "string":
data = opt;
break;
case "boolean":
write = opt;
break;
}
if (!data && typeof(data) != "number") data = "";
else if (!(data instanceof Buffer || data instanceof Uint8Array)) data = jBD.Conver.toString(data);
write = write !== false;
if (!jBD.has(encoding, encodeType)) encoding = "utf8";
API.Make(dest, true);
fs[write ? "writeFileSync" : "appendFileSync"](dest, data, {encoding: encoding});
}
};
return API;
}, {module: module, exports: this}, ["Conver"], "FS");