OpenHarmony 应用如何使用@ohos.worker多线程进行批量文件读写与复制 原创
作者:苟晶晶
简介:
支持批量文件读写、复制等操作,支持使用@ohos.worker进行多线程开发。创先线程可以使用@ohos.worker
文档环境:
-
开发环境:Windows 11 家庭版
-
DevEco Studio版本:DevEco Studio 4.0 Release(4.0.0.600)
-
SDK版本:4.0.10.13
-
开发板型号:DAYU200(RK3568)
-
系统版本:OpenHarmony 4.1.5.2
演示 demo:
-
新建一个 Stage 框架的 demo 工程,在entryability/EntryAbility.ets中通过 let filesDir = this.context.filesDir;AppStorage.SetOrCreate(‘sanBoxFileDir’, filesDir);存储沙箱files路径信息,然后在pages/CopyFile.ets中通过public baseDir: string | undefined = AppStorage.Get(‘sanBoxFileDir’);拿到应用的沙箱files路径信息,通过文件操作接口在files下创建文件夹workerDir并创建以txt为后缀的文件。
-
通过接口fs.listFileSync(filesPathDir)获取workerDir文件夹下的所有文件并显示在list中。
-
用户点击多选框选择需要批量拷贝的文件,通过new worker.ThreadWorker(‘entry/ets/workers/WorkerCopy.ets’)创建worker线程并将拷贝文件的信息发送至worker线程,在该线程中通过fs.copyFileSync(srcPath, destPath)实现文件拷贝操作,文件拷贝成功之后向主线程发送拷贝成功消息:workerPort.postMessage({count: count,strFlag: true,listFileNames: listFileNames});
核心代码如下:
在沙箱路径下创建待拷贝的文件:
readyFilesToWorker(): void { let content = CONTENT + CONTENT + new Date() + '\n'; let workerDir = this.baseDir + '/workerDir'; try { if (!fs.accessSync(workerDir)) { fs.mkdirSync(workerDir); } Logger.info(TAG, 'readyFilesToWorker dpath = ' + workerDir); for (let i = 0; i < FILE_NUM; i++) { let myFile = ''; if (i < FILE_NUMBER) { myFile = workerDir + `/TestFile0${i + 1}.txt`; } else { myFile = workerDir + `/TestFile${i + 1}.txt`; } Logger.info(TAG, 'readyFilesToWorker myFile = ' + myFile); let file = fs.openSync(myFile, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE); fs.writeSync(file.fd, content); fs.closeSync(file); } Logger.info(TAG, 'readyFilesToWorker successful'); } catch (e) { Logger.error(TAG, `readyFilesToWorker has failed for: {message: ${(e as BusinessError).message}, code: ${(e as BusinessError).code}}`); } }
创建worker线程并发送拷贝的文件信息:
async workToCopyFiles(files: Array<string>, filePath: string): Promise<void> { try { Logger.info(TAG, 'WorkCreator start to create worker'); let destPath = filePath; Logger.info(TAG, 'Workerets destPath ' + destPath); if (!fs.accessSync(destPath)) { fs.mkdirSync(destPath); } if (fs.accessSync(destPath)) { fs.listFile(destPath).then((filenames) => { Logger.info(TAG, 'listFile succeed'); for (let i = 0; i < filenames.length; i++) { Logger.info(TAG, 'Workerets fileName: ' + filenames[i]); } }).catch((err: BusinessError) => { Logger.info(TAG, 'list file failed with error message: ' + err.message + ', error code: ' + err.code); }); } if (files !== null) { this.realFileNames.length = 0; for (let i = 0; i < files.length; i++) { if (files[i] === 'deletedTag') { continue; } this.realFileNames.push(files[i]); } } let count = this.realFileNames.length; for (let j = 0; j < count; j++) { Logger.info(TAG, 'workToCopyFiles this.realFileNames = ' + this.realFileNames[j]); } workerInstance = new worker.ThreadWorker('entry/ets/workers/WorkerCopy.ts'); if (this.realFileNames !== null) { let srcPath = this.baseDir + '/workerDir'; workerInstance.postMessage({ srcDir: srcPath, destDir: destPath, fileNames: this.realFileNames }); } workerInstance.onexit = (code): void => { Logger.info(TAG, `workerInstance::onexit has been exit ${code}`); }; workerInstance.onerror = (err): void => { Logger.info(TAG, `workerInstance::onerror has errors: ${JSON.stringify(err)}`); }; workerInstance.onmessageerror = (event): void => { Logger.info(TAG, `workerInstance::onmessageerror has errors: ${JSON.stringify(event)}`); }; workerInstance.onmessage = (message): void => { Logger.info(TAG, `workerInstance::onmessage receive data: ${JSON.stringify(message.data)}`); if (message.data.hasOwnProperty('count')) { Logger.info(TAG, `workerInstance::onmessage receive data length = ${message.data.count}`); this.filesCount = message.data.count; fileFlag = message.data.strFlag; this.flag = true; let fileName1: string | null = null; let fileName2: string | null = null; for (let i: number = 0; i < message.data.listFileNames.length; i++) { Logger.info(TAG, `Worker workerInstance::onmessage receive listFileNames: ${message.data.listFileNames[i]}`); } if (message.data.listFileNames[0] !== undefined && message.data.listFileNames[1] !== undefined && message.data.listFileNames[LIST_FILE_TWO] === undefined) { fileName1 = message.data.listFileNames[0] + '、'; fileName2 = message.data.listFileNames[1]; } else if (message.data.listFileNames[0] !== undefined && message.data.listFileNames[1] === undefined) { fileName1 = message.data.listFileNames[0]; fileName2 = ''; } else { fileName1 = message.data.listFileNames[0] + '、'; let copyFileLog: string | undefined = AppStorage.Get('copyFileLog5'); fileName2 = message.data.listFileNames[1] + copyFileLog; } AppStorage.SetOrCreate('fileListName1', fileName1); AppStorage.SetOrCreate('fileListName2', fileName2); let copyFileLog3: string | undefined = AppStorage.Get('copyFileLog3'); let copyFileLog4: string | undefined = AppStorage.Get('copyFileLog4'); let copyFileLog = '2、' + fileName1 + fileName2 + copyFileLog3 + 'copy' + copyFileLog4; if (fileName1 !== 'undefined、') { AppStorage.SetOrCreate('copyFileShowLog', copyFileLog); } else { AppStorage.SetOrCreate('copyFileShowLog', $r('app.string.workerLogChooseFile')); } Logger.info(TAG, `Worker workerInstance::onmessage receive count: ${JSON.stringify(this.filesCount)}`); } if (this.filesCount !== 0) { AppStorage.SetOrCreate('fileNumber', JSON.stringify(this.filesCount)); } else { AppStorage.SetOrCreate('fileNumber', '0'); AppStorage.SetOrCreate('fileListName1', ''); AppStorage.SetOrCreate('fileListName2', ''); } Logger.info(TAG, 'workerInstance::onmessage Finish to process data from WorkerCopy.ts'); workerInstance?.terminate(); }; while (!fileFlag) { await sleep(SLEEP_TIME); } } catch (e) { Logger.error(TAG, `Worker WorkCreator error package: message: ${(e as BusinessError).message}, code: ${(e as BusinessError).code}`); } }
worker线程实现拷贝:
import worker from '@ohos.worker'; import type { ThreadWorkerGlobalScope } from '@ohos.worker'; import Logger from '../common/Logger'; import fs from '@ohos.file.fs'; const workerPort: ThreadWorkerGlobalScope = worker.workerPort; const TAG: string = '[ConcurrentModule].[WorkerCopy]'; workerPort.onmessage = (message): void => { let srcPath: string = null; let destPath: string = null; let fileNames: string = message.data.fileNames; for (let i = 0; i < fileNames.length; i++) { srcPath = message.data.srcDir + '/' + fileNames[i]; Logger.info(TAG, ' srcPath ' + srcPath); destPath = message.data.destDir + '/' + fileNames[i]; Logger.info(TAG, ' destPath ' + destPath); try { fs.copyFileSync(srcPath, destPath); let countTest = fs.listFileSync(message.data.destDir).length; Logger.info(TAG, `Worker workerInstance::onmessage receive countTest: ${countTest}`); } catch (e) { Logger.error(TAG, 'WorkerCopy::copyFile has failed for: ' + JSON.stringify(e)); } } let listFileNames = []; listFileNames.length = 0; try { let count = fs.listFileSync(message.data.destDir).length; let listFiles = fs.listFileSync(message.data.destDir); Logger.info(TAG, 'listFile succeed'); for (let i = 0; i < listFiles.length; i++) { listFileNames[i] = listFiles[i]; Logger.info(TAG, `Worker workerInstance::onmessage receive listFileNames: ${listFileNames[i]}`); } workerPort.postMessage({ count: count, strFlag: true, listFileNames: listFileNames }); Logger.info(TAG, 'WorkerCopy::onmessage thread post message successfully'); } catch (e) { Logger.error(TAG, 'WorkerCopy::onmessage has failed for: ' + JSON.stringify(e)); } }; workerPort.onmessageerror = async (message): Promise<void> => { Logger.error(TAG, 'WorkerCopy::onmessageerror : ' + JSON.stringify(message)); }; workerPort.onerror = (e): void => { Logger.error(TAG, 'WorkerCopy::onerror : ' + JSON.stringify(e)); };