import fs = require('fs'); import * as paths from 'path'; import assert = require('assert'); export interface FileVo { url: string; fileName?: string; type?: FILE_TYPE; parent?: FileVo; layerIndex?: number; children?: FileVo[]; isLeaf?: boolean; } export enum FILE_TYPE { FILE, DIR } export class FileUtils { static save(url: string, data: any, callback?: (result: boolean) => void, charSet: string = 'UTF-8'): void { //父文件地址: this.exists(this.parentUrl(url), (ret: boolean) => { if (ret) { fs.writeFile(url, data, charSet, (err) => { if (err) throw err; if (callback) callback(true); }); } else { //创建目录 fs.mkdir(this.parentUrl(url), (err) => { if (err) throw err; fs.writeFile(url, data, charSet, (err) => { if (err) throw err; if (callback) callback(true); }); }); } }); } static parentUrl(url: string): string { return paths.resolve(url, '..'); } /** 当前地址是否存在 */ static exists(url: string, callback?: (ret: boolean) => void): void { if (!url) callback(false); fs.exists(url, callback); } /** 返回共有的相对目录 */ static relative(from: string, to: string): string { return paths.relative(from, to); } /** 以异步的方式获取目录列表文件,不会读取子文件夹 */ static getDirectionListAsync(url: string, callback: (list: FileVo[]) => void, thisObject: any): void { if (!url) { callback.apply(thisObject, null); return; } this.isDirectory(url, (state: boolean) => { if (state) { fs.readdir(url, (err, files: string[]) => { let nums: number = 0; let list: FileVo[] = []; files.forEach((file) => { if (err) throw err; let fullurl: string = url + file; fs.stat(fullurl, (err, stat) => { if (err) throw err; if (stat.isDirectory()) { let fileVo: FileVo = { url: fullurl }; fileVo.fileName = file; list.push(fileVo); } nums++; if (nums == files.length) { callback.apply(thisObject, [list]); } }); }); }); } }); } /** 判断当前地址是否为目录 */ static isDirectory(path: string, callback: (isDirectory?: boolean) => void): void { if (!path) { callback(false); return; } fs.stat(path, (error, stat) => { if (error) throw error; callback(stat.isDirectory()); }); } /** * 拷贝目录 */ static copyDir(from: string, to: string, callback?: Function, thisObject?: any): void { //先判断文件是否存在 if (fs.existsSync(from) && fs.existsSync(to)) { //先创建目录 let stats: fs.Stats = fs.statSync(from); if (stats.isDirectory()) { } } } static compute: number = 0; static getDirsSync(url: string, dirsObject: any): void { if (!dirsObject) { dirsObject = {}; } dirsObject.url = url; let files: string[] = fs.readdirSync(url); if (files.length > 0) { dirsObject.children = []; } this.compute++; for (let i: number = 0, l: number = files.length; i < l; i++) { let file: string = files[i]; let fullurl: string = url + '/' + file; let fsStat: fs.Stats = fs.statSync(fullurl); if (fsStat.isDirectory()) { let dirObject: any = {}; dirObject.parent = dirsObject; dirObject.url = fullurl; dirsObject.children.push(dirObject); this.getDirsSync(fullurl, dirObject); } } } static getDirs(url: string, dirsObject: any): void { if (!dirsObject) { dirsObject = {}; } this.compute++; dirsObject.url = url; fs.readdir(url, (err, files) => { if (err) throw ('err'); if (files.length > 0) { dirsObject.children = []; } for (let i: number = 0, l: number = files.length; i < l; i++) { let file: string = files[i]; let fullurl: string = url + "/" + file; fs.stat(fullurl, (err, stats: fs.Stats) => { if (stats.isDirectory()) { let dirObject: any = {}; dirObject.parent = dirsObject; dirObject.url = fullurl; dirsObject.children.push(dirObject); this.getDirs(fullurl, dirObject); } }); } }); } //拷贝文件 static copyFile(from: string, to: string): void { fs.exists(from, (fromExists) => { fs.readdir(from, (err, files) => { if (err) throw Error('error'); for (let i: number = 0, l: number = files.length; i < l; i++) { let file: string = files[i]; let fromFullurl: string = from + "/" + file; let toFullurl: string = to + "/" + file; fs.stat(fromFullurl, (err, stats) => { if (err) throw Error('error'); if (stats.isDirectory()) { //在目录地址创建目录 if (!fs.existsSync(toFullurl)) fs.mkdirSync(toFullurl); } else { //直接拷贝到目标目录去 fs.writeFileSync(toFullurl, fs.readFileSync(fromFullurl, 'utf-8')); } this.copyFile(fromFullurl, toFullurl); }); } }); }); } /** * 拷贝文件 */ static copyFileSync(from: string, to: string, onComplete?: Function, thisObject?: any): void { if (fs.existsSync(from) && fs.existsSync(to)) { fs.createReadStream(from).pipe(fs.createWriteStream(to)); if (onComplete) { onComplete.apply(thisObject, []); } } } /** * 同步获取目录列表 * @param url * @param filters 过滤文件 [".ts",".jpg",".jpeg","png","mp3"] */ static getDirectionListing(url: string, filters?: string[]): FileVo { if (!url) return null; let file: FileVo = { url: url, type: FILE_TYPE.DIR, layerIndex: 0, fileName: paths.basename(url) }; this._getDirectionListing(url, file, filters); return file; } private static _getDirectionListing(url: string, fileVo: FileVo, filters?: string[]): void { let urls: string[] = fs.readdirSync(url); fileVo.children = []; for (let i: number = 0, l: number = urls.length; i < l; i++){ let value: string = paths.join(url,urls[i]); let stat = fs.statSync(value); let isDirectory: boolean = stat.isDirectory(); let file: FileVo = { url: value, fileName: paths.basename(value), type: (isDirectory) ? FILE_TYPE.DIR : FILE_TYPE.FILE, parent: fileVo, layerIndex: fileVo.layerIndex + 1, isLeaf: !isDirectory }; if (!isDirectory) { let extension = paths.extname(value); //只有过滤出来的扩展名才放进去 let isPut: boolean = false; for (let j: number = 0, jl: number = filters.length; j < jl; j++){ if (filters[j] === extension) { isPut = true; break; } } if (isPut) { fileVo.children.push(file); } } else { fileVo.children.push(file); } if (isDirectory) this._getDirectionListing(value, file, filters); } } public static escapePath(path: string): string { if (!path) return ""; path = decodeURIComponent(path); if (path.indexOf("file:///") == 0) { path = path.slice(7); if (path.charAt(2) == ":") path = path.slice(1); } path = path.split("\\").join("/"); return path; } /** * 扫描文件夹 * @param dir {string} 目录路径 * @param exts {array} 目标文件扩展名 * @param onSelected {function} 遍历到一个文件的时候 function(path){} * @param target {object} 目标 */ public static select(dir: string, exts: string[], onSelected: Function, target: any): void { if (dir.charAt(dir.length - 1) == "/") dir = dir.slice(0, dir.length - 1); let stat: fs.Stats = null; try { stat = fs.statSync(dir); } catch (e) { } if (stat && stat.isFile()) { if (FileUtils.matchExt(dir, exts)) { dir = FileUtils.escapePath(dir); onSelected.call(target, dir); } return; } let items: string[]; try { items = fs.readdirSync(dir); } catch (e) { } if (!items) return; let dirList: string[] = []; for (let i: number = 0; i < items.length; i++) { let item: string = items[i]; let stat: fs.Stats = fs.statSync(dir + "/" + item); if (stat.isDirectory() && item != ".svn" && item != ".git") { dirList.push(dir + "/" + item); } else { FileUtils.select(dir + "/" + item, exts, onSelected, target); } } for (let i: number = 0; i < dirList.length; i++) { FileUtils.select(dirList[i], exts, onSelected, target); } } private static matchExt(path: string, exts: string[]): boolean { path = path.toLowerCase(); for (let i: number = 0; i < exts.length; i++) { if ( (path.lastIndexOf("." + exts[i]) == path.length - (exts[i].length + 1)) && (path.indexOf("." + exts[i]) != -1) ) return true; } return false; } }