【OpenHarmony文件管理子系统】文件访问接口mod_file解析

发布于:2025-09-05 ⋅ 阅读:(22) ⋅ 点赞:(0)

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. 异步操作模式

所有文件操作都采用异步模式,遵循以下流程:

  1. 参数解析:从JavaScript传入的参数中提取必要信息
  2. URI验证:通过CheckUri函数验证路径合法性
  3. 异步工作创建:使用napi_create_async_work创建异步任务
  4. 执行函数:在后台线程执行实际的文件操作
  5. 完成回调:将结果通过回调函数返回给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接口,涵盖了文件/目录的创建、删除、复制、移动、读写、权限检查等全部基础功能。

核心特性总结

  1. 全面的文件操作支持

    • 12个核心API接口,覆盖所有基础文件操作需求
    • 支持文件和目录的完整生命周期管理
    • 提供文本和二进制数据的读写能力
  2. 异步非阻塞架构

    • 所有操作采用异步模式,避免阻塞JavaScript主线程
    • 基于NAPI异步工作队列,确保高并发性能
    • 统一的回调机制,支持success、fail、complete三种回调类型
  3. 安全可靠的实现

    • 完整的URI验证机制,防止路径遍历攻击
    • 内存安全设计,使用RAII和智能指针管理资源
    • 详细的错误处理和错误码定义
  4. 高性能优化

    • 使用sendfile系统调用优化文件复制性能
    • 支持大文件分块读写,避免内存溢出
    • 递归操作支持,提高批量操作效率
  5. 跨平台兼容性

    • 基于标准POSIX文件系统API
    • 支持不同产品形态的特殊处理
    • 统一的接口设计,屏蔽底层差异

网站公告

今日签到

点亮在社区的每一天
去签到