安卓上 mmap读取并修改文件内容

上一篇是直接创建文件并写入内容。这次是读取文件内容,如果文件不存在则创建文件并写入内容。文件存在则修改内容。

直接修改下上一个demo, TestMmap类中增加一个native方法:

复制代码
public native String testMmap2(String path);

同样,头文件也增加这个方法声明,代码略。 cpp文件增加这个函数实现:

cpp 复制代码
extern "C"
JNIEXPORT jstring JNICALL Java_com_example_testmmap_TestMmap_testMmap2
        (JNIEnv *env, jobject, jstring path) { // 判断文件不存在则创建文件,写入内容。存在则修改内容
    const char *file_path = env->GetStringUTFChars(path, nullptr);
    if (file_path == nullptr) {
        return env->NewStringUTF("Failed to get file path");
    }

    long page_size = sysconf(_SC_PAGESIZE);
    LOGI("当前系统内存页大小: %ld 字节", page_size);

    // 打开文件(智能判断是否存在)
    int fd = open(file_path, O_RDWR);  // 先尝试以读写方式打开现有文件
    bool is_new_file = false;

    if (fd == -1) {
        // 文件不存在 -> 创建新文件
        LOGI("文件不存在,正在创建新文件...");
        fd = open(file_path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); // O_CREAT表示文件不存在则创建
        if (fd == -1) {
            LOGI("创建文件失败: %s", file_path);
            env->ReleaseStringUTFChars(path, file_path);
            return env->NewStringUTF("Failed to create file");
        }
        // 设置初始大小为 4KB(对齐页大小)
        if (ftruncate(fd, page_size) == -1) {
            LOGI("设置文件大小失败");
            close(fd);
            env->ReleaseStringUTFChars(path, file_path);
            return env->NewStringUTF("Failed to set file size");
        }
        is_new_file = true;
    }

    // 获取文件实际大小
    struct stat st;
    if (fstat(fd, &st) == -1) {
        LOGI("获取文件状态失败");
        close(fd);
        env->ReleaseStringUTFChars(path, file_path);
        return env->NewStringUTF("Failed to get file stat");
    }
    size_t file_size = st.st_size;
    LOGI("当前文件大小: %zu 字节", file_size);

    // 建立内存映射
    void* mapped_mem = mmap(nullptr, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (mapped_mem == MAP_FAILED) {
        LOGI("mmap 映射失败");
        close(fd);
        env->ReleaseStringUTFChars(path, file_path);
        return env->NewStringUTF("mmap failed");
    }

    // 读取内容并修改
    char *content = (char *)mapped_mem;
    if (is_new_file) {
        // 新文件:写入初始内容
        const char *initial_msg = "Vicky du,平安喜乐";
        strcpy(content, initial_msg);
        LOGI("新文件写入初始内容: %s", content);
    } else {
        // 现有文件:读取当前内容,然后修改
        LOGI("修改前的内容: %s", content);

        // 在末尾追加
        std::string current_content(content);
        std::string append_text = " love u ";
        std::string new_content = current_content + append_text;

        // 安全检查:确保新内容不超过文件大小(留一个字节给结尾的 '\0')
        if (new_content.length() < file_size) {
            strcpy(content, new_content.c_str());
            LOGI("修改后的内容: %s", content);
        } else {
            // 空间不足时的降级方案:覆盖写一段新文本
            const char *fallback_msg = "三人行,必有我师。";
            strcpy(content, fallback_msg);
            LOGI("内容过长,已覆盖写入: %s", content);
        }
    }

    // 可选:强制刷盘
     msync(mapped_mem, file_size, MS_SYNC);

    // 清理资源
    munmap(mapped_mem, file_size);
    close(fd);
    env->ReleaseStringUTFChars(path, file_path);

    return env->NewStringUTF("mmap 读取并修改完成!");
}

MainActivity 写测试代码:

Kotlin 复制代码
val path = filesDir.absolutePath + "/test2.txt"
val result = TestMmap().testMmap2(path)
Log.i("MainActivity", result ?: "Mmap result is null")

运行:

ok. 再一次运行:

ok. 可以看到文件内容修改成新的字符串了。

相关推荐
Sirens.1 小时前
MySQL表设计进阶-约束范式连接索引与事务
android·数据库·mysql
二流小码农5 小时前
鸿蒙开发:实现文本渐变效果
android·ios·harmonyos
光头闪亮亮6 小时前
Fyne ( go跨平台GUI )项目实战-项目开发必备基础知识(中)
android·c++·go
光头闪亮亮6 小时前
Fyne ( go跨平台GUI )项目实战-项目开发必备基础知识(上)
android·sqlite·go
光头闪亮亮6 小时前
Fyne ( go跨平台GUI )项目实战-项目开发必备基础知识(下)
android·c++·go
Ch_champion7 小时前
2018年之前的Android 项目上使用的技术点(及第三方库)
android
龚礼鹏7 小时前
RK Android16 wifi 投屏失败问题排查
android
晓梦林9 小时前
[ACTF2020 新生赛]BackupFile学习笔记
android·笔记·学习
ITmaster073110 小时前
告别 IDE?Android CLI 来了,开发进入 AI Agent 时代
android·ide·人工智能