想了解更多关于开源的内容,请访问:
51CTO 开源基础软件社区
https://ost.51cto.com
OpenHarmony是由开放原子开源基金会(OpenAtom Foundation)孵化及运营的开源项目,目标是面向全场景、全连接、全智能时代,基于开源的方式,搭建一个智能终端设备操作系统的框架和平台,促进万物互联产业的繁荣发展。
监听机制是一种常见的计算机安全技术,它可以监控计算机系统中的各种活动,以便及时发现和处理安全问题。文件监听具有重要的现实意义,对文件进行监听,企业可以及时发现员工不当处理敏感信息和意外泄漏信息的情况,采取行动避免数据泄露。
本文以文件管理FileManager为例,介绍文件监听的应用实现以此了解@ohos.file.fs模块中涉及的接口的使用方法。
一、开发环境准备
下载并安装DevEco Studio,建议使用DevEco Studio 3.1 Release (Build Version: 3.1.0.500, built on April 28, 2023)及以上版本:
- DevEco Studio下载链接
- 下载sample仓库源码:
- sample仓源码路径
下载源码之后将FileManager工程导入DevEco Studio,首先对工程进行自动化签名,然后进行编译构建生成HAP应用安装包,安装应用示例之前,请先查看"README_zh.md"文件来确认应用示例是否为stage模型,若为Stage模型需要查看entry/src/main路径下的module.json5文件中的"deviceType"字段来确认该应用支持的设备类型;否则为FA模型,查看entry/src/main路径下的config.json文件中的"deviceType"字段来确认该应用示例支持的设备类型,两种模型都可尝试通过修改该字段使其可以在相应类型的设备上运行。文件管理FileManager为stage模型,支持设备为rk3568。安装运行之后,即可在设备上查看应用示例运行效果,以及进行相关调试。
二、实现
文件管理新增功能为文件监听,使用@ohos.file.fs模块watcher接口对文件、文件夹进行监控,添加相应监听后对文件进行增加、删除、修改操作后日志信息显示出相应监听日志,停止相应监听后对文件进行增加、删除、修改操作后日志信息无变化。
在使用接口时需要查看并配置接口对应的权限,监听文件时使用了系统接口,需要配置系统应用签名,可以参考特殊权限配置方法 ,把配置文件中的“app-feature”字段信息改为“hos_system_app”,再将“apl”字段信息改为“system_core”。另外,监听文件使用了API10接口,因此本工程仅支持API10版本的SDK。
1、流程图
OpenHarmony 文件监听开发样例介绍-开源基础软件社区
2、实现过程
(1)增加监听
使用数组watcherEvent保存监听变动的事件集,使用组件TextPickerDialog选择监听变动事件集,当用户选择一个监听事件添加监听时,调用startWatcher()方法进行监听,并将其保存到已添加监听事件WatcherList数组中。
src/main/ets/pages/WatcherFile.ets:
TextPickerDialog.show({
range: this.watcherEvent,
selected: this.select,
onAccept: (value: TextPickerResult) => {
this.select = Number(value.index);
this.eachEvent = this.watcherEvent[this.select];
this.myWatcher.startWatcher(this.eachEvent);
this.eventArray.push(this.eachEvent); // 新增列表项数据
}
})
在startWatcher()方法中,根据需要添加的监听事件使用fs.createWatcher()创建Watcher对象,用来监听文件或目录变动,调用watcher.start()开启监听,当监听事件发生一次,回调将会获取监听事件相关日志。
src/main/ets/filemanager/fileFs/MyWatcher.ts:
startWatcher(watcherName: string): void {
let watcherDir: string = this.baseDir + '/watcherDir';
Logger.info(TAG, `${watcherName}-startWatcher start path = ${watcherDir}`);
if (this.watcherCodeMap.has(watcherName)) { // 是否存在key 'watchName': true
try {
Logger.info(TAG, `${watcherName}-startWatcher has watchName`);
let watcher: fs.Watcher = fs.createWatcher(watcherDir, this.watcherCodeMap.get(watcherName), (data) => { //获取key对应的value
AppStorage.SetOrCreate('eventLog', JSON.stringify(data.event));
AppStorage.SetOrCreate('fileNameLog', data.fileName);
AppStorage.SetOrCreate('cookieLog', JSON.stringify(data.cookie));
Logger.info(TAG, `${watcherName}-startWatcher :{event: ${data.event}, fileName: ${data.fileName}, cookie: ${data.cookie}}`);
});
watcher.start();
setTimeout(async () => {
this.watcherList.push(watcher);
}, this.timeOut);
Logger.info('watcherList is ' + JSON.stringify(this.watcherList));
} catch (e) {
Logger.error(TAG, `${watcherName}-startWatcher has failed for: {message: ${e.message}, code: ${e.code}}`);
}
} else {
Logger.info(TAG, `${watcherName}-startWatcher does not in watcherCodeMap`);
}
}
(2)停止监听
当用户选择一个监听停止监听时,调用stopWatcher()方法停止监听,并将已添加监听事件WatcherList数组中该监听事件移除。
src/main/ets/pages/WatcherFile.ets:
TextPickerDialog.show({
range: showEventArray,
selected: this.selectDel,
onAccept: (value: TextPickerResult) => {
this.selectDel = Number(value.index);
this.myWatcher.stopWatcher(this.myWatcher.watcherList[this.selectDel], this.selectDel);
this.eventArray.splice(this.selectDel, 1); // 删除列表项数据
showEventArray.splice(this.selectDel, 1);
}
})
在stopWatcher()方法中,调用watcher.stop()停止监听,当停止监听的事件发生时,不再产生监听日志。
src/main/ets/filemanager/fileFs/MyWatcher.ts:
stopWatcher(watcher: fs.Watcher, index: number): void {
if (watcher !== null) {
watcher.stop();
setTimeout(async () => {
this.watcherList.splice(index, 1);
}, this.timeOut);
Logger.info(TAG, 'stopWatcher successful');
} else {
Logger.info(TAG, 'stopWatcher null');
}
}
(3)增加文件
当对应用沙箱文件或文件夹添加IN_CREATE监听后,在沙箱文件路径下新增一个文件,应用内则会打印出相应监听日志,使用fs.openSync打开文件,fs.writeSync方法对文件进行写入内容,fs.closeSync关闭文件。在沙箱路径下增加一个文件的具体实现方法如下所示:
src/main/ets/filemanager/fileFs/MyWatcher.ts:
addFileToWatcher(path: string): void {
let content = CONTENT + '\n';
try {
let addFile = this.baseDir + '/watcherDir/' + path;
Logger.info('addFileToWatcher addFile = ' + addFile);
let file = fs.openSync(addFile, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE | fs.OpenMode.TRUNC);
fs.writeSync(file.fd, content);
fs.closeSync(file);
} catch (e) {
Logger.error(TAG, `addFileToWatcher has failed for: {message: ${e.message}, code: ${e.code}}`);
}
}
(4)删除文件
当对应用沙箱文件或文件夹添加IN_DELETE监听后,在沙箱文件路径下删除一个文件,应用内则会打印出相应监听日志,使用fs.unlink删除文件。在沙箱路径下删除一个文件的具体实现方法如下所示:
src/main/ets/filemanager/fileFs/MyWatcher.ts:
deleteFileToWatcher(path: string): void {
try {
let deleteFile = this.baseDir + '/watcherDir/' + path;
Logger.info(TAG, 'deleteFileToWatcher deleteFile = ' + deleteFile);
fs.unlink(deleteFile).then(() => {
Logger.info(TAG, 'deleteFileToWatcher file succeed');
}).catch((err) => {
Logger.info(TAG, 'deleteFileToWatcher file failed with error message: ' + err.message + ', error code: ' + err.codeor);
});
} catch (e) {
Logger.error(TAG, `readyFileToWatcher has failed for: {message: ${e.message}, code: ${e.code}}`);
}
}
(5)修改文件
当对应用沙箱文件或文件夹添加IN_MODIFY监听后,在沙箱文件路径下对一个文件内容进行修改,应用内则会打印出相应监听日志,(注意:若只修改文件名,应用内不会打印监听日志)。使用fs.renameSync对文件名进行修改,使用fs.openSync打开文件,fs.writeSync方法对文件进行写入内容,fs.closeSync关闭文件。在沙箱路径下修改一个文件的具体实现方法如下所示:
src/main/ets/filemanager/fileFs/MyWatcher.ts:
modifyFileToWatcher(oldName: string, newName: string, content: string): number {
// 重命名文件
let filePath = null;
if (newName.trim() === oldName.trim()) {
filePath = this.baseDir + '/watcherDir/' + oldName;
Logger.info('modifyFileToWatcher The new file name is the same as the old file name');
} else {
try {
let srcFile = this.baseDir + '/watcherDir/' + oldName;
Logger.info('modifyFileToWatcher srcFile = ' + srcFile);
let dstFile = this.baseDir + '/watcherDir/' + newName;
filePath = dstFile;
Logger.info('modifyFileToWatcher dstFile = ' + dstFile);
fs.renameSync(srcFile, dstFile);
} catch (e) {
Logger.info(`modifyFileToWatcher -readyFileRW-creat has failed for: {message: ${e.message}, code: ${e.code}}`);
}
}
// 修改文件内容
Logger.info('modifyFileContentToWatcher filePath = ' + filePath);
try {
/* 修改文件内容时必须以fs.OpenMode.TRUNC打开文件,如果文件存在且以只写或读写的方式打开文件,则将其长度裁剪为零。这样修改文件内容时,若修改后的文件 * 比修改前小,也会正确修改,否则修改后文件的文件比未修改前小时,则修改错误。
*/
let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE | fs.OpenMode.TRUNC);
let writeLen = fs.writeSync(file.fd, content);
Logger.info('modifyFileContentToWatcher write data to file succeed and size is:' + writeLen);
fs.closeSync(file);
let fileRead = fs.openSync(filePath, fs.OpenMode.READ_WRITE);
let buf = new ArrayBuffer(BUFFER);
this.fileSize = fs.readSync(fileRead.fd, buf);
let resultPut = bufferToString(buf);
Logger.info('modifyFileContentToWatcher Read num = ' + this.fileSize);
Logger.info('modifyFileContentToWatcher Read resultPut = ' + resultPut);
fs.closeSync(fileRead);
Logger.info('modifyFileContentToWatcher write data to file succeed and fileSize is:' + this.fileSize);
} catch (e) {
Logger.info(`-readyFileRW-creat has failed for: {message: ${e.message}, code: ${e.code}}`);
}
return this.fileSize;
}
}
测试
sample功能完成之后,需要对开发完成的功能进行测试,此时就需要增加自动化测试用例实现对功能的基本测试。UiTest可以通过简洁易用的API提供查找和操作界面控件能力,支持用户开发基于界面操作的自动化测试脚本。如何编写UI测试用例参考编写UI测试脚本,测试执行完毕后可直接在DevEco Studio中查看测试结果,如下所示:
总结
通过使用这个示例,开发者可以快速掌握文件监听的实现方法,并将其运用到自己的应用中,实现更强大和丰富的功能。同时,这个示例也提供了一个学习和交流的平台,开发者可以与其他开发者分享经验和技巧,共同推动OpenHarmony生态的发展。
想了解更多关于开源的内容,请访问:
51CTO 开源基础软件社区
https://ost.51cto.com