Android FileObserver 用法

项目中有个需要,需要根据接收后台推送的文件,然后拷贝到指定目录。这个功能用FileObserver 可以实现,当监测目录有新文件时,会触发FileObserver.onEvent(),在onEvent 里拷贝文件就可以了。

 private void startFileObserverThread(){
    Runnable structexce = new Runnable() {
        public void run() {
            int flags = FileObserver.CREATE|FileObserver.MOVED_TO;//1.在监测路径中新建文件、子文件夹或将文件、子文件夹移动到监测路径
            
            mObserver = new FileObserver(SRC_PATH, flags) {
                public void onEvent(int event, String path) {//2.监测事件发生,触发onEvent
                    targetFile = null;
                    File[] files = new File(SRC_PATH).listFiles();
                    if(files==null){
                        return;
                    }
                    
                    try {
                        Thread.sleep(10000);//3.加个延时,等后台把文件传完
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    
                    for(int i=0; i<files.length; i++){
                        File f = files[i];
                        if(f.getName().matches("\\S*\\.zip$") && f.isFile()){
                            Log.d(TAG, "find target file: " +f.getPath());
                            targetFile = f;
                            break;                                
                        }
                    }
                    if ( targetFile != null) {

                        for(int j=0; j<10; j++){//4.以防万一,最多拷贝10次

                            try {
                                                          
                                copy(targetFile.getPath(), DST_FILE);
                            } catch (IOException e) {
                                Log.e(TAG,  "Could not copy animation.zip");
                            }
                            
                            try {
                                Thread.sleep(2000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                                                           
                            md5src = getFileMD5(targetFile);
                            md5dst = getFileMD5(new File(DST_FILE));
                            if (md5src != null && md5dst != null && md5src.equals(md5dst))//5.md5校验通过,认为拷贝成功
                                break;
                            
                        }
                        
                        if (md5src != null && md5dst != null && md5src.equals(md5dst)) {
                            
                            File[] namefiles = new File(NAME_PATH).listFiles();//6.将文件名同名文件记录在NAME_PATH路径下
                            if(namefiles!=null){
                                Log.d(TAG,NAME_PATH + " : is not empty");
                                    for(int i=0; i<namefiles.length; i++){
                                    File fi = namefiles[i];
                                    removeFile(fi.getPath());
                                    
                                }
                            }

                            String name[] = targetFile.getName().split("\\.zip");
                            
                            File zipname = new File(NAME_PATH +"/" + name[0]);
                            Log.d(TAG, "path = " + zipname.getPath());
                            
                            try {
                            FileWriter fileWritter = new FileWriter(zipname.getPath(),true);
                            fileWritter.write(md5dst);//7.记录文件md5值,以供后台校验
                            fileWritter.close();
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                                                            
                        }
                        removeFile(targetFile.getPath());//8.删除原文件
                    }
                    
                }
            };
            mObserver.startWatching();//9.开如检测
        }
    };
    Thread tFileObsv = new Thread(structexce);
    tFileObsv.start();

}

上面用到的文件删除、文件拷贝、md5计算也一并贴出来吧:

private boolean removeFile(String path) {
        Log.d(TAG, "starting removing " + path);
        File file = new File(path);
        if (null == file) {
            return false;
        }

        if (!file.exists()) {
            Log.d(TAG, "rm file not exists: " + path);
            return true;
        }

        if (!file.delete()) {
            Log.d(TAG, "rm error: " + path);
            return false;
        }
        Log.d(TAG, " removing " + path + " succedeed");
        return true;
    }
private void copy(String src, String dst) throws IOException {
        Log.d(TAG, " copying " + src + " to " + dst);
        InputStream in = new FileInputStream(src);
        OutputStream out = null;
        byte[] buf = new byte[1024*1024*80];
        int len;

        try {
            out = new FileOutputStream(dst);
            try {
                while ((len = in.read(buf)) > 0) {
                    out.write(buf, 0, len);
                }
                out.flush();

            } finally {
                out.close();
            }
        } finally {
            in.close();
        }
    }
public static String getFileMD5(File file) {
        if (!file.isFile()) {
            return null;
        }
        MessageDigest digest = null;
        FileInputStream in = null;
        byte buffer[] = new byte[1024];
        int len;
        try {
            digest = MessageDigest.getInstance("MD5");
            in = new FileInputStream(file);
            while ((len = in.read(buffer, 0, 1024)) != -1) {
                digest.update(buffer, 0, len);
            }
            in.close();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        BigInteger bigInt = new BigInteger(1, digest.digest());
        return bigInt.toString(16);
 }

问题总结

  1. 因为要记录后台推送的文件名,我就创建了一个文件名同名的文件,并在该文件中写入原文件的MD5值以供校验。但是起初我把该文件创建在监测路径下,这就导致有文件传来 -> 触发 onEvent -> 记录文件名 -> onEvent,这样onEvent就嵌套了,我曾尝试在onEvent 中先stopWatching,在onEvent 最后再重新startWatching,但这样还是不行,看了一下源码中stopWatching的说明,运行中的事件可能会继续上报(Some events may be in process, so events may continue to be reported even after this method completes. )。所以改在其他路径下创建文件了。
  2. 考虑到文件推送过程中有断电的可能,在开机时又检查了一下监测路径并清空。
  3. 创建监测路径是在device/rockchip/rk3288/init.rk3288.rc中:
on post-fs-data
    mkdir /data/media/XXX   0777 system  sdcard_rw

由于/data/media目录是在on post-fs-data 时创建的:

on post-fs-data
    # we will remap this as /mnt/sdcard with the sdcard fuse tool
    mkdir /data/media 0770 media_rw media_rw

所以一开时我写成:

on post-fs
    mkdir /data/media/XXX   0777 system  sdcard_rw

创建路径失败。

  1. 读写权限设置
    Android 文件系统权限定义在system/core/include/private/android_filesystem_config.h 中:
...
#define AID_MEDIA_RW      1023  /* internal media storage write access */
#define AID_MTP           1024  /* MTP USB driver access */
#define AID_UNUSED2       1025  /* deprecated, DO NOT USE */
#define AID_DRMRPC        1026  /* group for drm rpc */
#define AID_NFC           1027  /* nfc subsystem */
#define AID_SDCARD_R      1028  /* external storage read access */
...

内部存储读写权限group是1023,所以在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java 中加入1023 group:

String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "com.android.server.SystemServer",
        };
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值