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

相关推荐
其实防守也摸鱼14 小时前
Fastjson 反序列化漏洞(JNDI注入)
android·数据库·安全·oracle·自动化·fastjson·反序列化
狗凯之家源码网16 小时前
微博图床 PHP 系统搭建与实战应用指南
android·开发语言·php
消失的旧时光-194316 小时前
(第一篇)JNI 多线程到底难在哪:从 Linux Thread 到 JNIEnv
android·jni·ndk
逗脑IDE19 小时前
零基础学ESP32:蓝牙控制舵机——手机一点,舵机就转!
android·智能手机
清霜之辰19 小时前
骁龙 8397 舱驾融合平台端侧大模型部署:7B 模型本地推理与 64GB 内存账本
android
烽火聊员20 小时前
Android屏幕卡顿traces.txt拉取查看
android·java·android studio
只睡四小时21 小时前
JS 手写 D-pad 空间导航:电视端焦点引擎实战
android·开发语言·前端·javascript·ecmascript·hls·空间导航
恋猫de小郭21 小时前
Android 原生的 Compose A2UI 也来了,你还抱着 XML 养老吗?
android·前端·flutter
程序媛_1 天前
【JMeter】准备token文件
android·jmeter
维克兜率天1 天前
【维克】弹性策略:用“乖离率“捕捉超跌反弹
android·开发语言·python·深度学习·kotlin·量化