安卓上 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. 可以看到文件内容修改成新的字符串了。

相关推荐
文人sec5 小时前
MySQL主库出问题了,从库怎么办?备库为什么会延迟好几个小时?
android·数据库·mysql
hai_android5 小时前
不用 AIDL,手把手教你手写 Binder 代理类
android·kotlin
mmsx6 小时前
osmdroid 地图实战 03|地图的"分层世界":离线方案、图层模型与 Overlay 体系
android·前端
张文是假的啊7 小时前
IOC依赖注入问题:@Primary 和 @Qualifier的使用
android
换元不配限7 小时前
ConstraintLayout核心用法详解(三):引导线、屏障、组和占位
android·placeholder·barrier·约束布局·guideline
心平气和量大福大8 小时前
android studio(AS)工具-调试-统计总行数
android·ide·android studio
你的坚定10 小时前
SurfaceFlinger合成一帧的完整流程
android
爱笑鱼12 小时前
Android 系统启动机制(七):进入 SystemServer.main() 以后,system_server 还是一个空进程吗?
android·linux
好安静12 小时前
SurfaceFlinger 合成一帧的完整流程
android
alexhilton12 小时前
架构测试为何需要双视图
android·kotlin·android jetpack