Android 打开文件后向文件写数据,但数据并不能实时保存到磁盘

本文探讨了解决手机重启后无法记录状态的问题,包括在不同目录下创建文件、使用SystemProperties、SharePreferences及数据库存储方法。重点介绍了通过在数据库中存储flag并在手机重启后正确读取的方法。此外,还分享了使用sync()函数实时将数据写入磁盘的技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    最近在做一个项目,该项目需要通过JNI 在C 层加载dlopen 一个.so 文件,然而执行该.so 的函数时会由于不确定的原因导致手机系统重启(注意是整个手机重启,不是App 挂了)。现在有一个需求:在系统崩溃之前记录一个flag,如果执行没有崩溃就清除这个flag;否则等下次手机重启后再次执行前检查该flag,以此来判断手机是否重启过。

    让人抓狂的是试过很多方法,这个flag 总是记录不下来,手机一崩溃重启数据就丢失了。

    1. 在/data/data/包名/file/...  目录下创建文件,将flag写入到文件write,flush,close

        结果:可能是由于linux 文件系统的cache 机制,尽管flush 了,当手机重启后读该文件却是null,没有写入任何内容。甚至尝试过两次open,write,flush,都没有用。


    2. 在/data/local/tmp 目录下创建文件,将flag写入到文件write,flush,close

        结果:Permission denied,没有权限在该目录下创建文件


    3. SystemProperties.set(“persist.”); 

        结果:Android系统没有SystemProperties 函数,只能通过反射写属性。但是带 “persist.”的属性普通user 无权限


    4. SharePreferences 

        结果:尝试用SharePreferences来存储flag,仍然失败,当手机重启后读不到该flag


    5. 直接写数据库SQLiteDatabase

       结果:成功写入,当手机重启后能够读到该flag,欣喜若狂。不明其理,反正测试每次都可以正确保存,问题解决!

     写入示例代码:

        SQLiteDatabase database = DatabaseHelper.getInstance(context).getWritableDatabase();
        try {
            if (database != null) {
                ContentValues value = new ContentValues();
                value.put(DatabaseHelper.REBOOT_CRASH_COLUMN, "");
                database.update(DatabaseHelper.DATABASE_TABLE_NAME, value, null, null);
            }
        } catch (Exception e) {
            //TODO
        }
        
        if (database != null) {
            database.close();
        }


     读取示例代码:
        SQLiteDatabase database = DatabaseHelper.getInstance(context).getWritableDatabase();
        String crashInfo = null;
        Cursor cursor = null;
        try {
            if (database != null) {
                String[] columns = { column };
                cursor = database.query(DatabaseHelper.DATABASE_TABLE_NAME, columns, null, null, null, null, null);
                if (null != cursor && cursor.getCount() > 0) {
                    cursor.moveToFirst();
                    do {
                        crashInfo = cursor.getString(cursor.getColumnIndex(column));
                    } while(cursor.move(1)); 
                } 
            } 
        } catch (Exception e) {
            //TODO
        }
        
        if (cursor != null) {
            cursor.close();
        }
        
        if (database != null) {
            database.close();
        }


问题补充:

最近和同事又讨论起这个问题,找到另一个解决办法。其实文件 open、write完之后,调用一下sync()函数,就可以实时将数据写到磁盘的文件系统上(flush 函数并不能实时写磁盘,这一点要注意)!

    private boolean writeFile(File targetFile) {
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(targetFile);
            byte[] temp = new byte[]{‘a’,’b’,’c’,’d’,’e’};
            out.write(temp, 0, 5);
            if (out != null) {
                out.getFD().sync();
                out.close();
            }
            return true;

        } catch (Exception e) {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            return false;
        }
    }

在C层同样也可以调用fsync()函数:

#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

const char* journal_filename = “journal.log”;

void write_journal_entry (char* entry)
{
    int fd = open (journal_filename, O_WRONLY | O_CREAT | O_APPEND, 0660);
    write (fd, entry, strlen (entry));
    write (fd, “\n”, 1);

    fsync (fd);
    close (fd);
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值