网站如何不被百度搜到网站主页面设计哪个好
OpenHarmony文件访问接口mod_file模块
概述
mod_file模块是OpenHarmony分布式文件系统(DistributedFS)中负责文件操作的核心JavaScript接口模块。该模块基于Node-API(NAPI)技术,为JavaScript应用提供了完整的文件系统操作能力,包括文件/目录的创建、删除、复制、移动、读写等基础功能。
模块架构
1. 文件组织结构
interfaces/kits/js/src/mod_file/
├── module.cpp              # 模块入口文件
├── common_func.h/.cpp      # 通用工具函数
└── class_file/             # File类实现├── file_n_exporter.h   # 接口定义头文件└── file_n_exporter.cpp # 核心实现文件(1454行)
2. 核心组件
2.1 模块入口(module.cpp)
static napi_value Export(napi_env env, napi_value exports)
{std::vector<unique_ptr<NExporter> > products;products.emplace_back(make_unique<FileNExporter>(env, exports));for (auto &&product : products) {if (!product->Export()) {HILOGE("INNER BUG. Failed to export class %{public}s for module file", product->GetClassName().c_str());return nullptr;}}return exports;
}NAPI_MODULE(file, Export)
模块采用工厂模式,通过FileNExporter类导出所有文件操作接口。
2.2 通用工具函数(common_func)
struct CommonFunc {static std::tuple<bool, napi_ref, napi_ref, napi_ref> GetCallbackHandles(napi_env env, napi_value object);
};
提供统一的回调函数处理机制,支持success、fail、complete三种回调类型。
接口设计
1. 导出的API接口
mod_file模块共导出12个核心API:
| 接口名称 | 功能描述 | 参数类型 | 
|---|---|---|
mkdir | 创建目录 | {uri: string, recursive: boolean} | 
rmdir | 删除目录 | {uri: string, recursive: boolean} | 
get | 获取文件/目录信息 | {uri: string, recursive: boolean} | 
list | 列出目录内容 | {uri: string} | 
copy | 复制文件/目录 | {srcUri: string, dstUri: string} | 
move | 移动文件/目录 | {srcUri: string, dstUri: string} | 
delete | 删除文件/目录 | {uri: string} | 
access | 检查文件/目录访问权限 | {uri: string} | 
writeText | 写入文本内容 | {uri: string, text: string, append: boolean} | 
writeArrayBuffer | 写入二进制数据 | {uri: string, buffer: ArrayBuffer, position: number, append: boolean} | 
readText | 读取文本内容 | {uri: string} | 
readArrayBuffer | 读取二进制数据 | {uri: string, length: number, position: number} | 
2. 数据结构定义
2.1 文件信息结构
struct FileInfo {int32_t length = 0;              // 文件大小int64_t lastModifiedTime = 0;    // 最后修改时间std::string type = "";           // 文件类型(file/dir)std::string uri = "";            // 文件URI
};
2.2 异步回调信息结构
每种操作都有对应的异步回调信息结构,以AsyncMkdirCallbackInfo为例:
struct AsyncMkdirCallbackInfo {napi_env env = nullptr;                    // NAPI环境napi_async_work asyncWork = nullptr;       // 异步工作句柄napi_ref callback[3] = { 0 };             // 回调函数引用数组bool recursive = false;                    // 是否递归创建std::string url = "";                      // 目标路径int result = DEFAULT_RESULT;               // 操作结果int errorType = -1;                        // 错误类型
};
核心实现机制
1. 异步操作模式
所有文件操作都采用异步模式,遵循以下流程:
- 参数解析:从JavaScript传入的参数中提取必要信息
 - URI验证:通过
CheckUri函数验证路径合法性 - 异步工作创建:使用
napi_create_async_work创建异步任务 - 执行函数:在后台线程执行实际的文件操作
 - 完成回调:将结果通过回调函数返回给JavaScript
 
2. 关键实现函数
2.1 URI验证机制
bool CheckUri(napi_env env, string &path)
{// 检查路径长度限制if (path.length() > PATH_MAX) {return false;}// 检查路径格式和权限// 实现路径安全验证逻辑return true;
}
2.2 文件操作核心函数
目录创建(MkdirExec):
void MkdirExec(napi_env env, void *data)
{auto *asyncCallbackInfo = (AsyncMkdirCallbackInfo *)data;string path = asyncCallbackInfo->url;asyncCallbackInfo->result = FAILED;asyncCallbackInfo->errorType = FILE_IO_ERROR;if (GetRealPath(path) == ENOENT) {path = UriToAbsolute(path);if (asyncCallbackInfo->recursive && Mkdirs(path)) {asyncCallbackInfo->result = SUCCESS;} else if (mkdir(path.c_str(), DIR_FAULT_PERM) != FAILED) {asyncCallbackInfo->result = SUCCESS;}}
}
文件复制(CopyExec):
void CopyExec(napi_env env, void *data)
{auto *asyncCallbackInfo = (AsyncCopyCallbackInfo *)data;string path = asyncCallbackInfo->url;string pathDst = asyncCallbackInfo->urlDst;asyncCallbackInfo->result = FAILED;asyncCallbackInfo->errorType = FILE_IO_ERROR;if (GetRealPath(path) == ENOENT) {asyncCallbackInfo->errorType = FILE_PATH_ERROR;return;}struct stat statbf;if (stat(path.c_str(), &statbf) == FAILED) {asyncCallbackInfo->errorType = FILE_IO_ERROR;return;}int retval;if (S_ISREG(statbf.st_mode)) {retval = FileCopy(path, pathDst);  // 文件复制} else if (S_ISDIR(statbf.st_mode)) {retval = DirCopy(path, pathDst);   // 目录复制}if (retval == SUCCESS) {asyncCallbackInfo->result = SUCCESS;} else {asyncCallbackInfo->errorType = retval;}
}
文件移动(MoveExec):
void MoveExec(napi_env env, void *data)
{auto *asyncCallbackInfo = (AsyncMoveCallbackInfo *)data;string path = asyncCallbackInfo->url;string pathDst = asyncCallbackInfo->urlDst;asyncCallbackInfo->result = FAILED;asyncCallbackInfo->errorType = FILE_IO_ERROR;if (GetRealPath(path) == ENOENT) {asyncCallbackInfo->errorType = FILE_PATH_ERROR;return;}struct stat statbf;if (stat(path.c_str(), &statbf) == FAILED) {asyncCallbackInfo->errorType = FILE_IO_ERROR;return;}if (S_ISREG(statbf.st_mode)) {int retval = FileCopy(path, pathDst);if (retval == SUCCESS) {if (remove(path.c_str()) == SUCCESS) {asyncCallbackInfo->result = SUCCESS;}} else {asyncCallbackInfo->errorType = retval;}} else if (S_ISDIR(statbf.st_mode)) {int retval = DirCopy(path, pathDst);if (retval == SUCCESS) {if (Rmdirs(path)) {asyncCallbackInfo->result = SUCCESS;}} else {asyncCallbackInfo->errorType = retval;}}
}
文件删除(DeleteExec):
void DeleteExec(napi_env env, void *data)
{auto *asyncCallbackInfo = (AsyncDeleteCallbackInfo *)data;string path = asyncCallbackInfo->url;asyncCallbackInfo->result = FAILED;int statPath = GetRealPath(path);if (statPath == ENOENT) {asyncCallbackInfo->errorType = FILE_PATH_ERROR;} else if (statPath == COMMON_NUM::ZERO && remove(path.c_str()) != FAILED) {asyncCallbackInfo->result = SUCCESS;} else {asyncCallbackInfo->errorType = FILE_IO_ERROR;}
}
文本写入(WriteTextExec):
void WriteTextExec(napi_env env, void *data)
{auto *asyncCallbackInfo = (AsyncWriteCallbackInfo *)data;string path = asyncCallbackInfo->url;string text = asyncCallbackInfo->text;asyncCallbackInfo->result = FAILED;asyncCallbackInfo->errorType = FILE_IO_ERROR;int fd = -1;int statPath = GetRealPath(path);if (statPath == COMMON_NUM::ZERO || statPath == ENOENT) {if (asyncCallbackInfo->append) {fd = open(path.c_str(), O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);} else {fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);}if (fd != FAILED) {if (write(fd, text.c_str(), text.length()) != FAILED) {asyncCallbackInfo->result = SUCCESS;}close(fd);}} else {asyncCallbackInfo->errorType = FILE_IO_ERROR;}
}
二进制数据写入(WriteArrayBufferExec):
void WriteArrayBufferExec(napi_env env, void *data)
{auto *asyncCallbackInfo = (AsyncWriteBufferCallbackInfo *)data;string path = asyncCallbackInfo->url;asyncCallbackInfo->result = FAILED;asyncCallbackInfo->errorType = FILE_IO_ERROR;int fd = -1;int statPath = GetRealPath(path);if (statPath == COMMON_NUM::ZERO || statPath == ENOENT) {if (asyncCallbackInfo->append) {fd = open(path.c_str(), O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);} else {fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);lseek(fd, asyncCallbackInfo->position, SEEK_CUR);}if (fd != FAILED) {if (write(fd, asyncCallbackInfo->buffer, asyncCallbackInfo->len) != FAILED) {asyncCallbackInfo->result = SUCCESS;}close(fd);}} else {asyncCallbackInfo->errorType = FILE_IO_ERROR;}
}
文本读取(ReadTextExec):
void ReadTextExec(napi_env env, void *data)
{auto *asyncCallbackInfo = (AsyncReadCallbackInfo *)data;string path = asyncCallbackInfo->url;asyncCallbackInfo->result = FAILED;asyncCallbackInfo->errorType = FILE_IO_ERROR;int statPath = GetRealPath(path);if (statPath == COMMON_NUM::ZERO) {FDGuard fdg;fdg.SetFD(open(path.c_str(), O_RDONLY));struct stat buf;int result = stat(path.c_str(), &buf);if (fdg.GetFD() != FAILED && result != FAILED) {auto buffer = std::make_unique<char[]>(buf.st_size + 1);if (buffer == nullptr) {UniError(ENOMEM).ThrowErr(env);return;}if (read(fdg.GetFD(), buffer.get(), buf.st_size) != FAILED) {asyncCallbackInfo->result = SUCCESS;asyncCallbackInfo->text = std::string(buffer.get());}}} else {asyncCallbackInfo->errorType = FILE_PATH_ERROR;}
}
二进制数据读取(ReadArrayBufferExec):
void ReadArrayBufferExec(napi_env env, void *data)
{auto *asyncCallbackInfo = (AsyncReadBufferCallbackInfo *)data;string path = asyncCallbackInfo->url;asyncCallbackInfo->result = FAILED;asyncCallbackInfo->errorType = FILE_IO_ERROR;int statPath = GetRealPath(path);if (statPath == COMMON_NUM::ZERO) {FDGuard fdg;fdg.SetFD(open(path.c_str(), O_RDONLY));struct stat buf;int result = stat(path.c_str(), &buf);if (fdg.GetFD() != FAILED && result != FAILED) {int32_t begin = (buf.st_size < asyncCallbackInfo->position) ? buf.st_size : asyncCallbackInfo->position;int32_t len = (asyncCallbackInfo->length == COMMON_NUM::ZERO) ? (buf.st_size - begin) : asyncCallbackInfo->length;auto buffer = std::make_unique<char[]>(len + 1);if (buffer == nullptr) {UniError(ENOMEM).ThrowErr(env);return;}lseek(fdg.GetFD(), begin, SEEK_CUR);if (read(fdg.GetFD(), buffer.get(), len) != FAILED) {asyncCallbackInfo->result = SUCCESS;asyncCallbackInfo->len = len;asyncCallbackInfo->contents = std::string(buffer.get());}}} else {asyncCallbackInfo->errorType = FILE_PATH_ERROR;}
}
目录删除(RmdirExec):
void RmdirExec(napi_env env, void *data)
{auto *asyncCallbackInfo = (AsyncRmdirCallbackInfo *)data;string path = asyncCallbackInfo->url;asyncCallbackInfo->result = FAILED;asyncCallbackInfo->errorType = FILE_IO_ERROR;int statPath = GetRealPath(path);if (statPath == COMMON_NUM::ZERO) {if (asyncCallbackInfo->recursive && Rmdirs(path)) {asyncCallbackInfo->result = SUCCESS;} else if (remove(path.c_str()) != FAILED) {asyncCallbackInfo->result = SUCCESS;}} else if (statPath == ENOENT) {asyncCallbackInfo->errorType = FILE_PATH_ERROR;}
}
文件访问权限检查(AccessExec):
void AccessExec(napi_env env, void *data)
{auto *asyncCallbackInfo = (AsyncAccessCallbackInfo *)data;string path = asyncCallbackInfo->url;asyncCallbackInfo->result = FAILED;int statPath = GetRealPath(path);if (statPath == ENOENT) {asyncCallbackInfo->errorType = FILE_PATH_ERROR;} else if (statPath == COMMON_NUM::ZERO) {asyncCallbackInfo->result = SUCCESS;} else {asyncCallbackInfo->errorType = FILE_IO_ERROR;}
}
2.3 辅助工具函数
递归目录创建(Mkdirs):
bool Mkdirs(string path)
{for (size_t i = 1; i < path.length(); ++i) {if (path[i] == '/') {path[i] = '\0';if (access(path.c_str(), 0) != 0 && mkdir(path.c_str(), DIR_FAULT_PERM) == FAILED) {return false;}path[i] = '/';}}if (path.length() <= 0 || access(path.c_str(), 0) == 0 || mkdir(path.c_str(), DIR_FAULT_PERM) == FAILED) {return false;}return true;
}
递归目录删除(Rmdirs):
bool Rmdirs(const string &path)
{DIR *pDir;struct dirent *ptr = nullptr;if (!(pDir = opendir(path.c_str()))) {return false;}while ((ptr = readdir(pDir)) != nullptr) {if (strcmp(ptr->d_name, ".") != 0 && strcmp(ptr->d_name, "..") != 0) {if ((ptr->d_type == DT_DIR && Rmdirs(path + "/" + ptr->d_name)) ||remove((path + "/" + ptr->d_name).c_str()) == 0) {} else {closedir(pDir);return false;}}}closedir(pDir);if (rmdir(path.c_str()) != 0) {return false;}return true;
}
文件复制(FileCopy):
int FileCopy(const string& srcPath, const string& dstPath)
{bool ret = FILE_IO_ERROR;string src = srcPath;string dest = dstPath;if (GetRealPath(src) == 0) {if (GetRealPath(dest) == ENOENT) {FDGuard sfd;sfd.SetFD(open(src.c_str(), O_RDONLY));struct stat attrSrc;if (stat(src.c_str(), &attrSrc) == FAILED) {return FILE_IO_ERROR;}dest = UriToAbsolute(dest);FDGuard ofd;ofd.SetFD(open(dest.c_str(), O_WRONLY | O_CREAT, attrSrc.st_mode));if (ofd.GetFD() != FAILED) {ssize_t bytes = sendfile(ofd.GetFD(), sfd.GetFD(), nullptr, attrSrc.st_size);if (bytes == attrSrc.st_size) {ret = SUCCESS;}}}}return ret;
}
目录复制(DirCopy):
int DirCopy(const string& srcPath, const string& dstPath)
{string src = srcPath;string dest = dstPath;if (GetRealPath(src) == ENOENT) {return FILE_PATH_ERROR;}if (GetRealPath(dest) == ENOENT) {struct stat attrSrc;if (stat(src.c_str(), &attrSrc) == FAILED || !S_ISDIR(attrSrc.st_mode)) {return FILE_IO_ERROR;}dest = UriToAbsolute(dest);if (mkdir(dest.c_str(), attrSrc.st_mode) == FAILED) {return FILE_IO_ERROR;}// 递归复制目录内容// ... 实现细节}return SUCCESS;
}
3. 错误处理机制
3.1 错误类型定义
constexpr int SUCCESS = 0;                    // 操作成功
constexpr int FAILED = -1;                    // 操作失败
constexpr int URI_PARAMER_ERROR = 202;        // URI参数错误
constexpr int FILE_IO_ERROR = 300;            // 文件IO错误
constexpr int FILE_PATH_ERROR = 301;          // 文件路径错误
3.2 回调函数实现
成功回调:
void CallBackSuccess(napi_env env, napi_ref successFuncRef, int32_t count, napi_value obj)
{napi_value results = nullptr;napi_value successFunc = nullptr;napi_value global = nullptr;napi_get_global(env, &global);napi_get_reference_value(env, successFuncRef, &successFunc);if (successFunc == nullptr) {return;}napi_call_function(env, global, successFunc, count, &obj, &results);
}
错误回调:
void CallBackError(napi_env env, napi_ref failFuncRef, string errorProp, int errorCode)
{napi_value argvFail[2] = { 0 };napi_value results = nullptr;napi_value failFunc = nullptr;napi_value global = nullptr;napi_get_global(env, &global);argvFail[0] = NVal::CreateUTF8String(env, errorProp).val_;argvFail[1] = NVal::CreateInt32(env, errorCode).val_;napi_get_reference_value(env, failFuncRef, &failFunc);if (failFunc == nullptr) {return;}napi_call_function(env, global, failFunc, COMMON_NUM::TWO, argvFail, &results);
}
技术特点
1. 异步非阻塞设计
- 所有文件操作都在后台线程执行,不会阻塞JavaScript主线程
 - 使用NAPI的异步工作队列机制,确保操作的并发性和响应性
 
2. 统一的回调机制
- 支持success、fail、complete三种回调类型
 - 提供统一的错误处理和结果返回机制
 
3. 路径安全验证
- 实现了完整的URI验证机制
 - 防止路径遍历攻击和非法路径访问
 
4. 递归操作支持
- 目录操作支持递归模式
 - 可以一次性创建或删除整个目录树
 
5. 跨平台兼容性
- 基于标准POSIX文件系统API
 - 支持不同产品形态(如可穿戴设备)的特殊处理
 
6. 文件操作类型支持
- 文件操作:支持普通文件的创建、删除、复制、移动、读写
 - 目录操作:支持目录的创建、删除、复制、移动、遍历
 - 权限检查:提供文件访问权限验证机制
 - 递归操作:支持目录的递归创建和删除
 
7. 数据读写机制
- 文本读写:支持UTF-8编码的文本文件操作
 - 二进制读写:支持ArrayBuffer格式的二进制数据处理
 - 位置控制:支持指定位置的文件读写操作
 - 追加模式:支持文件内容的追加写入
 
8. 内存安全设计
- FDGuard机制:使用RAII模式自动管理文件描述符
 - 智能指针:使用unique_ptr管理动态内存分配
 - 异常安全:确保资源在异常情况下正确释放
 
使用示例
1. 创建目录
import file from '@ohos.file.file';// 创建单个目录
file.mkdir({uri: "internal://app/test_dir",success: () => {console.log("目录创建成功");},fail: (err) => {console.error("目录创建失败:", err);},complete: () => {console.log("操作完成");}
});// 递归创建目录
file.mkdir({uri: "internal://app/parent/child/grandchild",recursive: true,success: () => {console.log("递归目录创建成功");}
});
2. 文件读写操作
// 写入文本文件
file.writeText({uri: "internal://app/test.txt",text: "Hello, HarmonyOS!",append: false,success: () => {console.log("文本写入成功");}
});// 读取文本文件
file.readText({uri: "internal://app/test.txt",success: (data) => {console.log("文件内容:", data);}
});// 写入二进制数据
const buffer = new ArrayBuffer(1024);
const view = new Uint8Array(buffer);
// ... 填充数据
file.writeArrayBuffer({uri: "internal://app/data.bin",buffer: buffer,position: 0,append: false,success: () => {console.log("二进制数据写入成功");}
});
3. 文件管理操作
// 复制文件
file.copy({srcUri: "internal://app/source.txt",dstUri: "internal://app/destination.txt",success: () => {console.log("文件复制成功");}
});// 移动文件
file.move({srcUri: "internal://app/old_location.txt",dstUri: "internal://app/new_location.txt",success: () => {console.log("文件移动成功");}
});// 删除文件
file.delete({uri: "internal://app/temp_file.txt",success: () => {console.log("文件删除成功");},fail: (err) => {console.error("文件删除失败:", err);}
});// 删除目录(递归)
file.rmdir({uri: "internal://app/old_directory",recursive: true,success: () => {console.log("目录删除成功");}
});// 检查文件访问权限
file.access({uri: "internal://app/important_file.txt",success: () => {console.log("文件可访问");},fail: (err) => {console.error("文件不可访问:", err);}
});// 获取文件信息
file.get({uri: "internal://app/document.pdf",success: (fileInfo) => {console.log("文件信息:", fileInfo);console.log(`文件名: ${fileInfo.uri}`);console.log(`文件大小: ${fileInfo.length} 字节`);console.log(`文件类型: ${fileInfo.type}`);console.log(`最后修改时间: ${fileInfo.lastModifiedTime}`);}
});// 列出目录内容
file.list({uri: "internal://app/documents",success: (fileList) => {console.log("目录内容:", fileList);fileList.forEach(file => {console.log(`文件: ${file.uri}, 类型: ${file.type}, 大小: ${file.length}`);});}
});
4. 高级文件操作示例
// 大文件分块读取
function readLargeFile(uri, chunkSize = 1024 * 1024) {let position = 0;let allData = new Uint8Array(0);function readChunk() {file.readArrayBuffer({uri: uri,length: chunkSize,position: position,success: (data) => {const newData = new Uint8Array(data);const combined = new Uint8Array(allData.length + newData.length);combined.set(allData);combined.set(newData, allData.length);allData = combined;position += newData.length;if (newData.length === chunkSize) {readChunk(); // 继续读取下一块} else {console.log("文件读取完成,总大小:", allData.length);// 处理完整数据}},fail: (err) => {console.error("读取失败:", err);}});}readChunk();
}// 文件备份功能
function backupFile(srcUri, backupUri) {file.copy({srcUri: srcUri,dstUri: backupUri,success: () => {console.log("文件备份成功");},fail: (err) => {console.error("文件备份失败:", err);}});
}// 批量文件操作
function batchFileOperations() {const files = ["internal://app/file1.txt","internal://app/file2.txt","internal://app/file3.txt"];let completed = 0;const total = files.length;files.forEach(fileUri => {file.delete({uri: fileUri,success: () => {completed++;console.log(`删除文件 ${fileUri} 成功 (${completed}/${total})`);if (completed === total) {console.log("所有文件删除完成");}},fail: (err) => {console.error(`删除文件 ${fileUri} 失败:`, err);}});});
}
性能优化
1. 内存管理
- 使用智能指针管理内存,避免内存泄漏
 - 及时释放NAPI引用和异步工作句柄
 
2. 错误处理优化
- 统一的错误码定义,便于问题定位
 - 详细的错误信息返回,提升调试体验
 
3. 并发控制
- 异步操作避免阻塞主线程
 - 支持多个文件操作并发执行
 
总结
mod_file模块作为OpenHarmony文件系统的核心接口,提供了完整、安全、高效的文件操作能力。该模块共实现了12个核心API接口,涵盖了文件/目录的创建、删除、复制、移动、读写、权限检查等全部基础功能。
核心特性总结
- 
全面的文件操作支持:
- 12个核心API接口,覆盖所有基础文件操作需求
 - 支持文件和目录的完整生命周期管理
 - 提供文本和二进制数据的读写能力
 
 - 
异步非阻塞架构:
- 所有操作采用异步模式,避免阻塞JavaScript主线程
 - 基于NAPI异步工作队列,确保高并发性能
 - 统一的回调机制,支持success、fail、complete三种回调类型
 
 - 
安全可靠的实现:
- 完整的URI验证机制,防止路径遍历攻击
 - 内存安全设计,使用RAII和智能指针管理资源
 - 详细的错误处理和错误码定义
 
 - 
高性能优化:
- 使用sendfile系统调用优化文件复制性能
 - 支持大文件分块读写,避免内存溢出
 - 递归操作支持,提高批量操作效率
 
 - 
跨平台兼容性:
- 基于标准POSIX文件系统API
 - 支持不同产品形态的特殊处理
 - 统一的接口设计,屏蔽底层差异
 
 
