首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >HarmonyOS API 20 FilePicker 文件选择与多来源文件处理实战

HarmonyOS API 20 FilePicker 文件选择与多来源文件处理实战

原创
作者头像
china马斯克
发布2025-12-04 15:50:23
发布2025-12-04 15:50:23
2830
举报

在 HarmonyOS 应用开发中,文件选择是高频场景需求,开发者经常需要实现:

  • 本地沙箱目录文件选择
  • 系统公共目录文件读取
  • 多格式文件筛选(文档、图片、音视频等)
  • 选择后文件的后续处理(预览、上传、解析)

如何基于 HarmonyOS API 20 提供的 FilePicker 能力,优雅实现跨目录、多格式的文件选择功能,并处理不同来源文件的权限与路径问题?这里我整理了一套完整的解决方案,希望可以帮助到大家。

我们先了解一下filepicker

FilePicker 核心优势

HarmonyOS API 20 的 FilePicker 组件(文件选择器)是系统提供的统一文件选择接口,相比自定义文件浏览方案,具备以下核心优势:

  1. 统一 API:无需关注底层目录结构,通过标准化参数实现多目录文件选择
  2. 格式兼容:天然支持文档、图片、音视频等常见格式筛选
  3. 权限合规:系统级组件自动处理文件访问权限,无需手动申请危险权限
  4. 体验一致:遵循鸿蒙系统设计规范,保证不同设备上的交互一致性

实战场景与完整代码

场景 1:本地沙箱文件选择(应用私有目录)

应用沙箱目录(如 filesDir、cacheDir)下的文件为应用私有资源,选择时需指定沙箱路径,适用于读取应用生成或下载的文件。

代码语言:txt
复制
import picker from '@ohos.file.picker';
import fs from '@ohos.file.fs';
import { BusinessError } from '@ohos.base';

@Entry
@Component
struct SandboxFilePickerDemo {
  private context = getContext(this);

  build() {
    Column() {
      Button('选择沙箱内PDF文件')
        .width('80%')
        .height(45)
        .backgroundColor('#3498DB')
        .fontColor(Color.White)
        .borderRadius(25)
        .margin({ top: 100 })
        .onClick(() => this.pickSandboxFile());
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5');
  }

  // 选择沙箱内文件
  private async pickSandboxFile() {
    try {
      // 1. 配置文件选择器参数
      const filePickerOptions: picker.FilePickerOptions = {
        // 指定沙箱目录路径
        uri: fs.fileUri.getUriFromPath(this.context.filesDir),
        // 筛选PDF格式文件
        fileTypeFilter: ['application/pdf'],
        // 支持多选
        multiple: false
      };

      // 2. 创建文件选择器实例
      const documentPicker = new picker.DocumentPicker();

      // 3. 打开文件选择器
      const result = await documentPicker.select(filePickerOptions);

      if (result.files.length > 0) {
        const selectedFile = result.files[0];
        console.info(`选中文件:${selectedFile.name},路径:${selectedFile.uri}`);
        
        // 4. 后续处理:如调用FilePreview预览(需导入filePreview模块)
        this.previewFile(selectedFile.uri, selectedFile.name);
      }
    } catch (err) {
      const error = err as BusinessError;
      console.error(`沙箱文件选择失败:code=${error.code}, message=${error.message}`);
    }
  }

  // 预览选中的文件
  private previewFile(fileUri: string, fileName: string) {
    import('@ohos.file.preview').then((filePreview) => {
      const previewInfo: filePreview.PreviewInfo = {
        title: fileName,
        uri: fileUri,
        mimeType: 'application/pdf'
      };

      filePreview.openPreview(this.context, previewInfo)
        .then(() => console.info('文件预览成功'))
        .catch((previewErr: BusinessError) => {
          console.error(`预览失败:code=${previewErr.code}, message=${previewErr.message}`);
        });
    });
  }
}

场景 2:系统公共目录文件选择(图片 / 文档 / 视频)

公共目录(如图片、文档、下载目录)存储系统级共享文件,选择时需指定对应媒体类型,适用于读取用户导入的外部文件。

代码语言:txt
复制
import picker from '@ohos.file.picker';
import { BusinessError } from '@ohos.base';

@Entry
@Component
struct PublicFilePickerDemo {
  private context = getContext(this);
  @State selectedFiles: Array<picker.SelectedFile> = [];

  build() {
    Column() {
      Text('公共目录文件选择')
        .fontSize(28)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 50, bottom: 30 });

      // 图片选择按钮
      Button('选择图片(PNG/JPG)')
        .width('80%')
        .height(45)
        .backgroundColor('#E74C3C')
        .fontColor(Color.White)
        .borderRadius(25)
        .margin({ bottom: 15 })
        .onClick(() => this.pickPublicFile('image'));

      // 文档选择按钮
      Button('选择办公文档(Word/Excel/PDF)')
        .width('80%')
        .height(45)
        .backgroundColor('#2ECC71')
        .fontColor(Color.White)
        .borderRadius(25)
        .margin({ bottom: 15 })
        .onClick(() => this.pickPublicFile('document'));

      // 选中文件列表
      List() {
        ForEach(this.selectedFiles, (file) => {
          ListItem() {
            Text(file.name)
              .fontSize(16)
              .padding(15)
              .width('100%')
              .backgroundColor(Color.White)
              .borderRadius(8)
              .margin({ bottom: 10 });
          }
        })
      }
      .width('80%')
      .height(200)
      .margin({ top: 30 });
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
    .alignItems(HorizontalAlign.Center);
  }

  // 选择公共目录文件
  private async pickPublicFile(fileType: 'image' | 'document' | 'video') {
    try {
      // 根据文件类型配置筛选条件
      let filePickerOptions: picker.FilePickerOptions = {};
      
      switch (fileType) {
        case 'image':
          filePickerOptions = {
            uri: 'file:///storage/emulated/0/Pictures',
            fileTypeFilter: ['image/png', 'image/jpeg'],
            multiple: true
          };
          break;
        case 'document':
          filePickerOptions = {
            uri: 'file:///storage/emulated/0/Documents',
            fileTypeFilter: [
              'application/pdf',
              'application/msword',
              'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
              'application/vnd.ms-excel',
              'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
            ],
            multiple: true
          };
          break;
        case 'video':
          filePickerOptions = {
            uri: 'file:///storage/emulated/0/Movies',
            fileTypeFilter: ['video/mp4', 'video/mkv'],
            multiple: false
          };
          break;
      }

      // 创建文件选择器并打开
      const documentPicker = new picker.DocumentPicker();
      const result = await documentPicker.select(filePickerOptions);

      if (result.files.length > 0) {
        this.selectedFiles = result.files;
        console.info(`成功选择${result.files.length}个文件`);
      }
    } catch (err) {
      const error = err as BusinessError;
      console.error(`公共文件选择失败:code=${error.code}, message=${error.message}`);
    }
  }
}

场景 3:选择文件后上传(结合网络请求)

文件选择后常需上传至服务器,以下示例实现选择文件后通过 HTTP 请求上传文件流。

代码语言:txt
复制
import picker from '@ohos.file.picker';
import fs from '@ohos.file.fs';
import request from '@ohos.net.http';
import { BusinessError } from '@ohos.base';

@Entry
@Component
struct FileUploadDemo {
  private context = getContext(this);
  @State uploadStatus: string = '未选择文件';

  build() {
    Column() {
      Text('文件选择与上传')
        .fontSize(28)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 50, bottom: 30 });

      Button('选择并上传文件')
        .width('80%')
        .height(45)
        .backgroundColor('#9B59B6')
        .fontColor(Color.White)
        .borderRadius(25)
        .onClick(() => this.pickAndUploadFile());

      Text(this.uploadStatus)
        .fontSize(16)
        .margin({ top: 30 })
        .fontColor(this.uploadStatus.includes('成功') ? '#2ECC71' : '#E74C3C');
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
    .alignItems(HorizontalAlign.Center);
  }

  // 选择文件并上传
  private async pickAndUploadFile() {
    try {
      // 1. 选择文件
      const filePickerOptions: picker.FilePickerOptions = {
        uri: 'file:///storage/emulated/0/Documents',
        fileTypeFilter: ['application/pdf', 'image/png'],
        multiple: false
      };

      const documentPicker = new picker.DocumentPicker();
      const result = await documentPicker.select(filePickerOptions);

      if (result.files.length === 0) {
        this.uploadStatus = '未选择任何文件';
        return;
      }

      const selectedFile = result.files[0];
      this.uploadStatus = `正在上传:${selectedFile.name}`;

      // 2. 读取文件流
      const file = await fs.open(selectedFile.uri, fs.OpenMode.READ_ONLY);
      const fileStream = fs.createStream(file.fd, {
        readStart: 0,
        readEnd: file.size - 1
      });

      // 3. 上传文件到服务器
      await this.uploadFileToServer(selectedFile.name, fileStream);

      // 4. 关闭文件流
      await fs.close(file);
    } catch (err) {
      const error = err as BusinessError;
      this.uploadStatus = `上传失败:${error.message}`;
      console.error(`文件处理失败:code=${error.code}, message=${error.message}`);
    }
  }

  // 上传文件到服务器
  private async uploadFileToServer(fileName: string, fileStream: fs.Stream) {
    // 创建HTTP请求
    const httpClient = request.createHttp();
    const uploadUrl = 'https://your-server-url/upload'; // 替换为实际上传接口

    try {
      // 配置请求参数
      const requestOptions: request.UploadRequestOptions = {
        url: uploadUrl,
        files: [
          {
            filename: fileName,
            name: 'file',
            stream: fileStream
          }
        ],
        header: {
          'Content-Type': 'multipart/form-data'
        }
      };

      // 发送上传请求
      const response = await httpClient.upload(requestOptions);

      if (response.responseCode === 200) {
        this.uploadStatus = `上传成功:${fileName}`;
        console.info('文件上传成功,响应:', response.result.toString());
      } else {
        this.uploadStatus = `上传失败:状态码${response.responseCode}`;
        console.error('文件上传失败,响应码:', response.responseCode);
      }
    } catch (err) {
      const error = err as BusinessError;
      this.uploadStatus = `上传异常:${error.message}`;
      console.error(`上传请求失败:code=${error.code}, message=${error.message}`);
    } finally {
      // 关闭HTTP客户端
      httpClient.destroy();
    }
  }
}

关键注意事项

1.权限配置:访问公共目录文件需在module.json5中配置对应权限:

代码语言:txt
复制
"requestPermissions": [
  {
    "name": "ohos.permission.READ_MEDIA_IMAGES",
    "reason": "需要读取图片文件",
    "usedScene": {
      "abilities": ["MainAbility"],
      "when": "always"
    }
  },
  {
    "name": "ohos.permission.READ_MEDIA_DOCUMENTS",
    "reason": "需要读取文档文件",
    "usedScene": {
      "abilities": ["MainAbility"],
      "when": "always"
    }
  }
]

2.格式筛选:fileTypeFilter需使用标准 MIME 类型,常见类型对应关系:

PDF:application/pdf

Word:application/msword(doc)、application/vnd.openxmlformats-officedocument.wordprocessingml.document(docx)

Excel:application/vnd.ms-excel(xls)、application/vnd.openxmlformats-officedocument.spreadsheetml.sheet(xlsx)

图片:image/png、image/jpeg、image/gif

视频:video/mp4、video/mkv

3.错误处理:需处理文件不存在、权限不足、网络异常等常见错误,通过BusinessError获取错误码进行针对性处理。

4.性能优化:选择大文件时建议使用流式读取,避免一次性加载整个文件到内存导致 OOM;多文件选择时限制最大选择数量。

总结

HarmonyOS API 20 的 FilePicker 组件提供了统一的文件选择解决方案,支持沙箱目录与公共目录的文件访问,结合 FilePreview 可实现文件预览,结合网络请求可实现文件上传。开发时需根据文件来源(沙箱 / 公共目录)选择合适的配置参数,做好权限申请与错误处理,确保功能的稳定性与用户体验。当然也要提醒一下大家,不同版本的 HarmonyOS 可能存在 API 差异,实际开发中需结合官方文档与设备系统版本进行适配调整。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • FilePicker 核心优势
  • 实战场景与完整代码
    • 场景 1:本地沙箱文件选择(应用私有目录)
    • 场景 2:系统公共目录文件选择(图片 / 文档 / 视频)
    • 场景 3:选择文件后上传(结合网络请求)
  • 关键注意事项
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档