next-ucap-messenger/electron-projects/ucap-webmessenger-electron/src/lib/file-util.ts
2019-11-11 15:53:39 +09:00

223 lines
6.1 KiB
TypeScript

import * as path from 'path';
import * as fse from 'fs-extra';
/**
*
* separator
* If the specified filename exists, the separator will be added before the incremental value such as: file{separator}2.jpg
* The default value is '-'.
*
* mode
* The mode allows you to specify which characters to use to generate the incremental value (the string after the separator)
* The default value is 'numeric'.
* 'numeric' Using the following characters: 1234567890
* 'alpha' Using the following characters: abcdefghijklmnopqrstuvwxyz
* 'ALPHA' Using the following characters: ABCDEFGHIJKLMNOPQRSTUVWXYZ
* 'alphanumeric' Using the following characters: 0123456789abcdefghijklmnopqrstuvwxyz
* 'ALPHANUMERIC' Using the following characters: 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ
* 'charset' You must specify the characters you wish to use in the charset option
*
* paddingCharacter && paddingSize
* If you wish to left-pad the incremental values with a character, use this option. Here's an example :
* var uniquefilename = require('uniquefilename');
* options = {mode: 'alpha', paddingCharacter: '0', paddingSize: 3};
* uniquefilename.get('/path/to/dir/file.jpg', options, function(filename) {
* // filename might be "/path/to/dir/file.jpg",
* // "/path/to/dir/file-002.jpg", "/path/to/dir/file-045.jpg", etc...
* // depending on the files that exist on your filesystem
* });
*
* alwaysAppend
* If alwaysAppend is true filenames will include the separator and attachment from the first request.
* So instead of file.jpg, file-2.jpg you'd get file-1.jpg, file-2.jpg.
*/
export interface UniqueFileNameOption {
separator?: string;
mode?:
| 'numeric'
| 'alpha'
| 'ALPHA'
| 'alphanumeric'
| 'ALPHANUMERIC'
| 'charset';
paddingCharacter?: string;
paddingSize?: number;
alwaysAppend?: boolean;
charset?: string;
}
const charsets = {
alpha: 'abcdefghijklmnopqrstuvwxyz',
alphanumeric: '0123456789abcdefghijklmnopqrstuvwxyz',
ALPHA: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
ALPHANUMERIC: '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
};
interface UniqueFile {
dir?: string;
ext?: string;
base?: string;
increment?: number;
}
export class FileUtil {
static blobToBuffer(blob: Blob): Promise<Buffer> {
if (typeof Blob === 'undefined' || !(blob instanceof Blob)) {
throw new Error('first argument must be a Blob');
}
return new Promise<Buffer>((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => {
resolve(Buffer.from(reader.result as ArrayBuffer));
};
reader.onerror = () => {
reader.abort();
reject(reader.error);
};
reader.readAsArrayBuffer(blob);
});
}
static uniqueFileName(
filePath: string,
options?: UniqueFileNameOption
): Promise<string> {
return new Promise<string>((resolve, reject) => {
const dir = path.dirname(filePath);
const ext = path.extname(filePath);
const base = path.basename(filePath, ext);
const uniqueFile: UniqueFile = {
dir,
ext,
base
};
options = options || {};
options.separator = options.separator || '-';
options.mode = options.mode || 'numeric';
if ('numeric' !== options.mode) {
if (charsets[options.mode]) {
options.charset = charsets[options.mode];
options.mode = 'charset';
} else if (
'charset' !== options.mode ||
('charset' === options.mode && !options.charset)
) {
options.mode = 'numeric';
}
}
if (options.paddingSize && !options.paddingCharacter) {
options.paddingCharacter = '0';
}
FileUtil.uniqueFileNameProcess(
uniqueFile,
options,
(fileName: string) => {
resolve(fileName);
}
);
});
}
private static uniqueFileNameProcess(
uniqueFile: UniqueFile,
options: UniqueFileNameOption,
callback: (fileName: string) => void
) {
let fileName: string;
let append = '';
if (options.alwaysAppend && !uniqueFile.increment) {
uniqueFile.increment = 1;
}
if (uniqueFile.increment) {
if ('numeric' === options.mode) {
append = '' + uniqueFile.increment;
} else {
append = FileUtil.numberToString(uniqueFile.increment, options.charset);
}
if (options.paddingSize) {
while (append.length < options.paddingSize) {
append = options.paddingCharacter + append;
}
}
append = options.separator + append;
}
fileName = path.join(
uniqueFile.dir,
uniqueFile.base + append + uniqueFile.ext
);
if (fse.existsSync(fileName)) {
if (uniqueFile.increment) {
uniqueFile.increment += 1;
} else {
uniqueFile.increment = 'numeric' === options.mode ? 2 : 1;
}
return FileUtil.uniqueFileNameProcess(uniqueFile, options, callback);
} else {
return callback(fileName);
}
}
private static numberToString(nbr: number, charset: string) {
const charsetLen = charset.length;
let strLen = 0;
let strThisLen = 0;
let tmp: number;
for (let maxpower = 20; maxpower >= 0; maxpower--) {
const maxvalue = FileUtil.sumOfPowerFromOne(charsetLen, maxpower);
if (maxvalue < nbr) {
strLen = maxpower + 1;
strThisLen = maxvalue + Math.pow(charsetLen, maxpower + 1) - maxvalue;
break;
}
}
if (0 === strLen) {
return null;
}
let str = '';
while (--strLen >= 0) {
if (strLen === 0) {
str += charset.charAt(nbr - 1);
break;
}
strThisLen = Math.pow(charsetLen, strLen);
const initial = FileUtil.sumOfPowerFromOne(charsetLen, strLen - 1);
for (tmp = charsetLen; tmp >= 1; tmp--) {
if (initial + tmp * strThisLen < nbr) {
break;
}
}
nbr -= tmp * strThisLen;
str += charset.charAt(tmp - 1);
}
return str;
}
private static sumOfPowerFromOne(base: number, maxpower: number) {
let value = 0;
for (let tmp = maxpower; tmp >= 1; tmp--) {
value += Math.pow(base, tmp);
}
return value;
}
}