如何为UWP并发文件追加代码添加异常处理?
处理C++/CX异步文件操作中的异常
我太懂这种挫败感了——C++/CX里的异步任务异常处理和普通同步代码完全不是一回事,你直接在外层套try-catch根本抓不到异步任务里蹦出来的异常,因为这些异常会被封装到task对象里,得用正确的姿势去捕获才行。
下面给你两种靠谱的处理方案,你可以根据需求选:
方案一:在任务延续中统一捕获异常
这种方法会捕获任务链中所有环节的异常(比如文件找不到、损坏、权限不够等),核心是用带task<void>参数的延续,然后调用get()触发异常抛出:
StorageFolder^ storageFolder = ApplicationData::Current->LocalFolder; concurrency::create_task(storageFolder->GetFileAsync(txtfile)) // 先执行文件追加的任务,把它返回给下一个延续 .then([](StorageFile^ sampleFile) { return concurrency::create_task(FileIO::AppendTextAsync(sampleFile, New_Program_Data)); }) // 用task<void>接收上一个任务,在这里处理异常 .then([](concurrency::task<void> previousTask) { try { previousTask.get(); // 这一步会抛出之前任务链里的所有未处理异常 } catch (Platform::Exception^ ex) { // 这里可以根据错误类型做不同处理 OutputDebugString(ex->Message->Data()); // 举个例子:如果是文件不存在,就创建后重试 if (ex->HResult == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) { auto folder = ApplicationData::Current->LocalFolder; concurrency::create_task(folder->CreateFileAsync(txtfile, CreationCollisionOption::OpenIfExists)) .then([](StorageFile^ newFile) { concurrency::create_task(FileIO::AppendTextAsync(newFile, New_Program_Data)); }); } // 还可以处理其他错误,比如权限不足、文件损坏等 else if (ex->HResult == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) { // 处理权限问题的逻辑 } } });
方案二:提前检查文件状态,主动避免异常
如果不想靠异常处理来应对文件不存在的情况,可以先用TryGetItemAsync检查文件是否存在,它不会在文件不存在时抛出异常,而是返回nullptr,这样你能主动分支处理:
StorageFolder^ storageFolder = ApplicationData::Current->LocalFolder; concurrency::create_task(storageFolder->TryGetItemAsync(txtfile)) .then([](IStorageItem^ item) { if (item != nullptr && item->IsOfType(StorageItemTypes::File)) { // 文件存在,直接追加数据 return concurrency::create_task(FileIO::AppendTextAsync(static_cast<StorageFile^>(item), New_Program_Data)); } else { // 文件不存在,创建后再追加 auto folder = ApplicationData::Current->LocalFolder; return concurrency::create_task(folder->CreateFileAsync(txtfile, CreationCollisionOption::OpenIfExists)) .then([](StorageFile^ newFile) { return concurrency::create_task(FileIO::AppendTextAsync(newFile, New_Program_Data)); }); } }) // 最后还是要加个异常处理,应对其他意外情况(比如文件损坏、权限问题) .then([](concurrency::task<void> previousTask) { try { previousTask.get(); } catch (Platform::Exception^ ex) { OutputDebugString(ex->Message->Data()); } });
几个关键注意点:
- 绝对不要在UI线程直接调用
task::get(),这会阻塞UI,导致界面卡顿甚至无响应,一定要放在异步延续里处理。 Platform::Exception^里的HResult是判断错误类型的关键,常见的错误码可以参考Windows API的定义,比如ERROR_FILE_NOT_FOUND对应文件不存在,ERROR_ACCESS_DENIED对应权限不足。
内容的提问来源于stack exchange,提问作者Gavin Hannah
相关产品推荐
相关产品推荐

