android监听文件和目录的创建删除移动等事件

android.os下的FileObserver类是一个用于监听文件访问、创建、修改、删除、移动等操作的监听器,基于linux的inotify。 FileObserver 是个抽象类,必须继承它才能使用。每个FileObserver对象监听一个单独的文件或者文件夹,如果监视的是一个文件夹,那么文件夹下所有的文件和级联子目录的改变都会触发监听的事件。 所能监听的事件类型如下: ACCESS,即文件被访问 MODIFY,文件被 修改 ATTRIB,文件属性被修改,如 chmod、chown、touch 等 CLOSE_WRITE,可写文件被 close CLOSE_NOWRITE,不可写文件被 close OPEN,文件被 open MOVED_FROM,文件被移走,如 mv MOVED_TO,文件被移来,如 mv、cp CREATE,创建新文件 DELETE,文件被删除,如 rm DELETE_SELF,自删除,即一个可执行文件在执行时删除自己 MOVE_SELF,自移动,即一个可执行文件在执行时移动自己 CLOSE,文件被关闭,等同于(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) ALL_EVENTS,包括上面的所有事件 这些都是FileObserver的静态共有属性。 下面举个例子说明一下其用法。 比如,我要监听sd卡的目录创建事件,新建一个类SDCardListener继承FileObserver:

scala 复制代码
import android.os.FileObserver;
import android.util.Log;

/**
 * sd卡上的目录创建监听器
 * @author chroya
 *
 */
public class SDCardListener extends FileObserver {

	public SDCardListener(String path) {
		/*
		 * 这种构造方法是默认监听所有事件的,如果使用super(String,int)这种构造方法,
		 * 则int参数是要监听的事件类型.
		 */
		super(path);
	}

	@Override
	public void onEvent(int event, String path) {		
		switch(event) {
		case FileObserver.ALL_EVENTS:
			Log.d("all", "path:"+ path);
			break;
		case FileObserver.CREATE:
			Log.d("Create", "path:"+ path);
			break;
		}
	}
}

onEvent是回调,系统监听到事件后会触发此事件,参数event就是上面所说的事件类型,根据类型,我们可以做相应的处理,参数path就是触发事件的目录。

然后使用它:

scss 复制代码
SDCardListener listener = new SDCardListener("/sdcard");
//开始监听
listener.startWatching();
/*
* 在这里做一些操作,比如创建目录什么的
*/
//最后停止监听
listener.stopWatching();

如果要在onEvent中做较多操作,最好用线程去做 ,以免因为阻塞接收不到后面的事件。 最后补充一点,比较重要 : FileObserver对象必须保持一个引用,确保不被垃圾收集器回收掉,否则就不会触发事件了。

让我们实现 FileObserver + 前台服务 的结合,确保在后台持续监听,即使应用被杀掉也能保持运行!下面分成几部分来讲解:

🚦一、前台服务基本结构

在 Android 中,前台服务需要:

  • 创建 Service 来管理 FileObserver
  • 创建通知,确保服务在前台运行,避免系统回收。
  • 启动服务时,绑定 FileObserver

🏗️二、创建前台服务

1. FileMonitorService.java

java 复制代码
java复制编辑import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.FileObserver;
import android.os.IBinder;
import android.util.Log;

public class FileMonitorService extends Service {
    private static final String TAG = "FileMonitorService";
    private static final String CHANNEL_ID = "FileMonitorChannel";

    private SDCardListener fileObserver;
    private String directoryPath = "/sdcard";  // 替换为你要监听的目录

    @Override
    public void onCreate() {
        super.onCreate();
        createNotificationChannel();
        startForeground(1, createNotification());
        startFileObserver();
        Log.d(TAG, "Service started and observer initialized.");
    }

    private void startFileObserver() {
        fileObserver = new SDCardListener(directoryPath);
        fileObserver.startWatching();
        Log.d(TAG, "Started watching: " + directoryPath);
    }

    private void stopFileObserver() {
        if (fileObserver != null) {
            fileObserver.stopWatching();
            Log.d(TAG, "Stopped watching: " + directoryPath);
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;  // 确保服务在被系统杀掉时重启
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        stopFileObserver();
        Log.d(TAG, "Service destroyed and observer stopped.");
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    CHANNEL_ID, "File Monitor Service", NotificationManager.IMPORTANCE_LOW);
            NotificationManager manager = getSystemService(NotificationManager.class);
            if (manager != null) {
                manager.createNotificationChannel(channel);
            }
        }
    }

    private Notification createNotification() {
        Notification.Builder builder = new Notification.Builder(this)
                .setContentTitle("File Monitoring Active")
                .setContentText("Watching directory: " + directoryPath)
                .setSmallIcon(android.R.drawable.ic_menu_info_details);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            builder.setChannelId(CHANNEL_ID);
        }
        return builder.build();
    }
}

2. SDCardListener.java

java 复制代码
java复制编辑import android.os.FileObserver;
import android.util.Log;

public class SDCardListener extends FileObserver {
    private static final String TAG = "SDCardListener";

    public SDCardListener(String path) {
        super(path, FileObserver.ALL_EVENTS);
    }

    @Override
    public void onEvent(int event, String path) {
        switch (event) {
            case FileObserver.CREATE:
                Log.d(TAG, "File created: " + path);
                break;
            case FileObserver.DELETE:
                Log.d(TAG, "File deleted: " + path);
                break;
            case FileObserver.MODIFY:
                Log.d(TAG, "File modified: " + path);
                break;
            case FileObserver.MOVED_FROM:
                Log.d(TAG, "File moved from: " + path);
                break;
            case FileObserver.MOVED_TO:
                Log.d(TAG, "File moved to: " + path);
                break;
            default:
                Log.d(TAG, "Event " + event + " on: " + path);
                break;
        }
    }
}

3. AndroidManifest.xml 中声明服务和权限

ini 复制代码
xml复制编辑<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

<application>
    <service
        android:name=".FileMonitorService"
        android:foregroundServiceType="dataSync" />
</application>

4. 启动/停止服务

你可以在 MainActivity 里启动/停止前台服务:

scala 复制代码
java复制编辑import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 启动服务
        Intent intent = new Intent(this, FileMonitorService.class);
        startForegroundService(intent);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 停止服务
        Intent intent = new Intent(this, FileMonitorService.class);
        stopService(intent);
    }
}

🎯五、运行效果

  1. 启动 App 后,通知栏显示"File Monitoring Active",服务进入前台。
  2. 任何对 /sdcard 目录的操作(如文件创建、删除、修改、移动等),都会触发 SDCardListener,输出日志。
  3. App 被杀掉后,服务依然存活,持续监听。即使系统回收,也会自动重启(START_STICKY)。

⚡六、优化建议

  • 递归监听子目录:
    FileObserver 不能自动递归监听所有子目录。如果需要递归监听,创建多个 FileObserver 对象,每个对象监听一个子目录。
  • 电量优化:
    FileObserver 是 native 的 inotify 实现,功耗较低,但频繁操作大目录时,建议加上事件合并、去抖动逻辑。
  • 异常处理:
    防止监听路径被删除、SD 卡拔出、权限丢失等意外情况引起的崩溃。
相关推荐
移动开发者1号18 分钟前
Android 大文件分块上传实战:突破表单数据限制的完整方案
android·java·kotlin
移动开发者1号26 分钟前
单线程模型中消息机制解析
android·kotlin
每次的天空3 小时前
Android第十五次面试总结(第三方组件和adb命令)
android
追随远方3 小时前
Android音频开发:Speex固定帧与变长帧编解码深度解析
android·音视频
消失的旧时光-19433 小时前
Android和硬件通信
android
0wioiw03 小时前
安卓基础(编译.Class)
android
0wioiw03 小时前
安卓基础(aar)
android
_一条咸鱼_3 小时前
Android Runtime链接(Linking)阶段准备工作(27)
android·面试·android jetpack
aqi004 小时前
FFmpeg开发笔记(六十四)使用国产的RedPlayer播放器观看网络视频
android·ffmpeg·音视频·直播·流媒体
雨白4 小时前
扩展函数和运算符重载
android