bowling-analysis-system
Version:
A comprehensive system for analyzing bowling techniques using video processing and metrics calculation
154 lines (136 loc) • 4.22 kB
JavaScript
/**
* @fileoverview File service for handling file operations
* @module utils/FileService
*/
const fs = require('fs');
const path = require('path');
const { promisify } = require('util');
// Promisify fs functions
const readFileAsync = promisify(fs.readFile);
const writeFileAsync = promisify(fs.writeFile);
const mkdirAsync = promisify(fs.mkdir);
const statAsync = promisify(fs.stat);
/**
* File service for handling file operations
*/
class FileService {
/**
* Read a file
* @param {string} filePath - Path to the file
* @param {Object} options - Read options
* @param {string} [options.encoding='utf8'] - File encoding
* @returns {Promise<string|Buffer>} File contents
*/
async readFile(filePath, options = {}) {
const encoding = options.encoding || 'utf8';
return readFileAsync(filePath, { encoding });
}
/**
* Write to a file
* @param {string} filePath - Path to the file
* @param {string|Buffer} data - Data to write
* @param {Object} options - Write options
* @param {string} [options.encoding='utf8'] - File encoding
* @param {boolean} [options.createDir=true] - Create directory if it doesn't exist
* @returns {Promise<void>}
*/
async writeFile(filePath, data, options = {}) {
const encoding = options.encoding || 'utf8';
const createDir = options.createDir !== false;
if (createDir) {
const dirPath = path.dirname(filePath);
await this.ensureDirectoryExists(dirPath);
}
return writeFileAsync(filePath, data, { encoding });
}
/**
* Ensure a directory exists
* @param {string} dirPath - Path to the directory
* @returns {Promise<void>}
*/
async ensureDirectoryExists(dirPath) {
try {
await mkdirAsync(dirPath, { recursive: true });
} catch (error) {
if (error.code !== 'EEXIST') {
throw error;
}
}
}
/**
* Check if a file exists
* @param {string} filePath - Path to the file
* @returns {Promise<boolean>} Whether the file exists
*/
async fileExists(filePath) {
try {
const stats = await statAsync(filePath);
return stats.isFile();
} catch (error) {
if (error.code === 'ENOENT') {
return false;
}
throw error;
}
}
/**
* List files matching a pattern
* @param {string} pattern - Glob pattern
* @param {Object} options - Options
* @param {boolean} [options.fullPaths=false] - Return full paths
* @returns {Promise<string[]>} Array of file paths
*/
async listFiles(pattern, options = {}) {
// Simple implementation without glob
const dir = path.dirname(pattern);
const files = fs.readdirSync(dir);
// Filter files based on pattern
const filePattern = path.basename(pattern).replace(/\*/g, '.*');
const regex = new RegExp(`^${filePattern}$`);
const matchedFiles = files.filter(file => regex.test(file));
if (options.fullPaths) {
return matchedFiles.map(file => path.resolve(dir, file));
}
return matchedFiles;
}
/**
* Resolve a path
* @param {string} basePath - Base path
* @param {string} relativePath - Relative path
* @returns {string} Resolved path
*/
resolvePath(basePath, relativePath) {
return path.resolve(basePath, relativePath);
}
/**
* Get the basename of a path
* @param {string} filePath - File path
* @param {string} [ext] - Extension to remove
* @returns {string} Basename
*/
getBasename(filePath, ext) {
return path.basename(filePath, ext);
}
/**
* Get the directory name of a path
* @param {string} filePath - File path
* @returns {string} Directory name
*/
getDirname(filePath) {
return path.dirname(filePath);
}
/**
* Get the extension of a path
* @param {string} filePath - File path
* @returns {string} Extension
*/
getExtension(filePath) {
return path.extname(filePath);
}
}
// Create default instance
const defaultFileService = new FileService();
module.exports = {
FileService,
defaultFileService
};