harmony 鸿蒙应用文件上传下载

  • 2025-06-12
  • 浏览 (8)

应用文件上传下载

应用可以将应用文件上传到网络服务器,也可以从网络服务器下载网络资源文件到本地应用文件目录。

上传应用文件

开发者可以使用上传下载模块(ohos.request)的上传接口将本地文件上传。文件上传过程使用系统服务代理完成,在api12中request.agent.create接口增加了设置代理地址参数,支持用户设置自定义代理地址。

说明:

当前上传应用文件功能。request.uploadFile方式仅支持上传应用缓存文件路径(cacheDir)下的文件,request.agent方式支持上传用户公共文件和应用缓存文件路径下的文件。

使用上传下载模块,需声明权限:ohos.permission.INTERNET。

以下示例代码演示两种将应用缓存文件路径下的文件上传至网络服务器的方式:

// 方式一:request.uploadFile
// pages/xxx.ets
import { common } from '@kit.AbilityKit';
import fs from '@ohos.file.fs';
import { BusinessError, request } from '@kit.BasicServicesKit';

@Entry
@Component
struct Index {
  build() {
    Row() {
      Column() {
        Button("上传").onClick(() => {
          // 获取应用文件路径
          // 请在组件内获取context,确保this.getUIContext().getHostContext()返回结果为UIAbilityContext
          let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
          let cacheDir = context.cacheDir;

          // 新建一个本地应用文件
          let file = fs.openSync(cacheDir + '/test.txt', fs.OpenMode.READ_WRITE|fs.OpenMode.CREATE);
          fs.writeSync(file.fd, 'upload file test');
          fs.closeSync(file);

          // 上传任务配置项
          let files: Array<request.File> = [
          //uri前缀internal://cache 对应cacheDir目录
            { filename: 'test.txt', name: 'test', uri: 'internal://cache/test.txt', type: 'txt' }
          ]
          let data: Array<request.RequestData> = [{ name: 'name', value: 'value' }];
          let uploadConfig: request.UploadConfig = {
            url: 'https://xxx',
            header: {
              'key1':'value1',
              'key2':'value2'
            },
            method: 'POST',
            files: files,
            data: data
          }

          // 将本地应用文件上传至网络服务器
          try {
            request.uploadFile(context, uploadConfig)
              .then((uploadTask: request.UploadTask) => {
                uploadTask.on('complete', (taskStates: Array<request.TaskState>) => {
                  for (let i = 0; i < taskStates.length; i++) {
                    console.info(`upload complete taskState: ${JSON.stringify(taskStates[i])}`);
                  }
                });
              })
              .catch((err: BusinessError) => {
                console.error(`Invoke uploadFile failed, code is ${err.code}, message is ${err.message}`);
              })
          } catch (error) {
            let err: BusinessError = error as BusinessError;
            console.error(`Invoke uploadFile failed, code is ${err.code}, message is ${err.message}`);
          }
        })
      }
    }
  }
}
// 方式二:request.agent
// pages/xxx.ets
import { common } from '@kit.AbilityKit';
import fs from '@ohos.file.fs';
import { BusinessError, request } from '@kit.BasicServicesKit';

@Entry
@Component
struct Index {
  build() {
    Row() {
      Column() {
        Button("上传").onClick(() => {
          // 获取应用文件路径
          // 请在组件内获取context,确保this.getUIContext().getHostContext()返回结果为UIAbilityContext
          let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
          let cacheDir = context.cacheDir;

          // 新建一个本地应用文件
          let file = fs.openSync(cacheDir + '/test.txt', fs.OpenMode.READ_WRITE|fs.OpenMode.CREATE);
          fs.writeSync(file.fd, 'upload file test');
          fs.closeSync(file);
          let attachments: Array<request.agent.FormItem> = [{
            name: "test",
            value: [
              {
                filename: "test.txt",
                path: "./test.txt",
              },
            ]
          }];
          let config: request.agent.Config = {
            action: request.agent.Action.UPLOAD,
            url: 'http://xxx',
            mode: request.agent.Mode.FOREGROUND,
            overwrite: true,
            method: "POST",
            headers: {
              'key1':'value1',
              'key2':'value2'
            },
            data: attachments,
            saveas: "./"
          };
          request.agent.create(context, config).then((task: request.agent.Task) => {
            task.start((err: BusinessError) => {
              if (err) {
                console.error(`Failed to start the upload task, Code: ${err.code}  message: ${err.message}`);
                return;
              }
            });
            task.on('progress', async(progress) => {
              console.warn(`/Request upload status ${progress.state}, uploaded ${progress.processed}`);
            })
            task.on('completed', async() => {
              console.warn(`/Request upload completed`);
              //该方法需用户管理任务生命周期,任务结束后调用remove释放task对象
              request.agent.remove(task.tid);
            })
          }).catch((err: BusinessError) => {
            console.error(`Failed to create a upload task, Code: ${err.code}, message: ${err.message}`);
          });
        })
      }
    }
  }
}

下载网络资源文件至应用文件目录

开发者可以使用上传下载模块(ohos.request)的下载接口将网络资源文件下载到应用文件目录。对已下载的网络资源文件,开发者可以使用基础文件IO接口(ohos.file.fs)对其进行访问,使用方式与应用文件访问一致。文件下载过程使用系统服务代理完成,在api12中request.agent.create接口增加了设置代理地址参数,支持用户设置自定义代理地址。

说明:

当前网络资源文件仅支持下载至应用文件目录。

使用上传下载模块,需声明权限:ohos.permission.INTERNET。

以下示例代码演示两种将网络资源文件下载到应用文件目录的方式:

// 方式一:request.downloadFile
// pages/xxx.ets
// 将网络资源文件下载到应用文件目录并读取一段内容
import { common } from '@kit.AbilityKit';
import fs from '@ohos.file.fs';
import { BusinessError, request } from '@kit.BasicServicesKit';
import { buffer } from '@kit.ArkTS';

@Entry
@Component
struct Index {
  build() {
    Row() {
      Column() {
        Button("下载").onClick(() => {
          // 获取应用文件路径
          // 请在组件内获取context,确保this.getUIContext().getHostContext()返回结果为UIAbilityContext
          let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
          let filesDir = context.filesDir;

          try {
            request.downloadFile(context, {
              url: 'https://xxxx/xxxx.txt',
              filePath: filesDir + '/xxxx.txt'
            }).then((downloadTask: request.DownloadTask) => {
              downloadTask.on('complete', () => {
                console.info('download complete');
                let file = fs.openSync(filesDir + '/xxxx.txt', fs.OpenMode.READ_WRITE);
                let arrayBuffer = new ArrayBuffer(1024);
                let readLen = fs.readSync(file.fd, arrayBuffer);
                let buf = buffer.from(arrayBuffer, 0, readLen);
                console.info(`The content of file: ${buf.toString()}`);
                fs.closeSync(file);
              })
            }).catch((err: BusinessError) => {
              console.error(`Invoke downloadTask failed, code is ${err.code}, message is ${err.message}`);
            });
          } catch (error) {
            let err: BusinessError = error as BusinessError;
            console.error(`Invoke downloadFile failed, code is ${err.code}, message is ${err.message}`);
          }
        })
      }
    }
  }
}
// 方式二:request.agent
// pages/xxx.ets
// 将网络资源文件下载到应用文件目录并读取一段内容
import { common } from '@kit.AbilityKit';
import fs from '@ohos.file.fs';
import { BusinessError, request } from '@kit.BasicServicesKit';
import { buffer } from '@kit.ArkTS';

@Entry
@Component
struct Index {
  build() {
    Row() {
      Column() {
        Button("下载").onClick(() => {
          // 获取应用文件路径
          // 请在组件内获取context,确保this.getUIContext().getHostContext()返回结果为UIAbilityContext
          let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
          let filesDir = context.filesDir;

          let config: request.agent.Config = {
            action: request.agent.Action.DOWNLOAD,
            url: 'https://xxxx/test.txt',
            saveas: 'xxxx.txt',
            gauge: true,
            overwrite: true,
            network: request.agent.Network.WIFI,
          };
          request.agent.create(context, config).then((task: request.agent.Task) => {
            task.start((err: BusinessError) => {
              if (err) {
                console.error(`Failed to start the download task, Code: ${err.code}  message: ${err.message}`);
                return;
              }
            });
            task.on('progress', async (progress) => {
              console.warn(`/Request download status ${progress.state}, downloaded ${progress.processed}`);
            })
            task.on('completed', async () => {
              console.warn(`/Request download completed`);
              let file = fs.openSync(filesDir + '/xxxx.txt', fs.OpenMode.READ_WRITE);
              let arrayBuffer = new ArrayBuffer(1024);
              let readLen = fs.readSync(file.fd, arrayBuffer);
              let buf = buffer.from(arrayBuffer, 0, readLen);
              console.info(`The content of file: ${buf.toString()}`);
              fs.closeSync(file);
              //该方法需用户管理任务生命周期,任务结束后调用remove释放task对象
              request.agent.remove(task.tid);
            })
          }).catch((err: BusinessError) => {
            console.error(`Failed to create a download task, Code: ${err.code}, message: ${err.message}`);
          });
        })
      }
    }
  }
}

下载网络资源文件至用户文件

开发者可以使用上传下载模块(ohos.request)的request.agent下载接口将网络资源文件下载到用户文件。

下载文档类文件

开发者可以通过调用DocumentViewPickersave()接口保存文件并获得用户文件的uri,将此uri作为Config的saveas字段值进行下载。

import { BusinessError, request } from '@kit.BasicServicesKit';
import { picker } from '@kit.CoreFileKit';
import { common } from '@kit.AbilityKit';

@Entry
@Component
struct Index {
  build() {
    Row() {
      Column() {
        Button("下载文档").width("50%").margin({ top: 20 }).height(40).onClick(async () => {
          // 创建文件管理器选项实例。
          const documentSaveOptions = new picker.DocumentSaveOptions();
          // 保存文件名(可选)。 默认为空。
          documentSaveOptions.newFileNames = ["xxxx.txt"];
          // 保存文件类型['后缀类型描述|后缀类型'],选择所有文件:'所有文件(*.*)|.*'(可选),如果选择项存在多个后缀(最大限制100个过滤后缀),默认选择第一个。如果不传该参数,默认无过滤后缀。
          documentSaveOptions.fileSuffixChoices = ['文档|.txt', '.pdf'];

          let uri: string = '';
          // 请在组件内获取context,确保this.getUIContext().getHostContext()返回结果为UIAbilityContext
          let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
          const documentViewPicker = new picker.DocumentViewPicker(context);
          await documentViewPicker.save(documentSaveOptions).then((documentSaveResult: Array<string>) => {
            uri = documentSaveResult[0];
            console.info('DocumentViewPicker.save to file succeed and uri is:' + uri);
          }).catch((err: BusinessError) => {
            console.error(`Invoke documentViewPicker.save failed, code is ${err.code}, message is ${err.message}`);
          })
          if (uri != '') {
            let config: request.agent.Config = {
              action: request.agent.Action.DOWNLOAD,
              url: 'https://xxxx/xxxx.txt',
              // saveas字段是DocumentViewPicker保存的文件的uri
              saveas: uri,
              gauge: true,
              // overwrite字段必须为true
              overwrite: true,
              network: request.agent.Network.WIFI,
              // mode字段必须为request.agent.Mode.FOREGROUND
              mode: request.agent.Mode.FOREGROUND,
            };
            try {
              request.agent.create(context, config).then((task: request.agent.Task) => {
                task.start((err: BusinessError) => {
                  if (err) {
                    console.error(`Failed to start the download task, Code: ${err.code}  message: ${err.message}`);
                    return;
                  }
                });
                task.on('progress', async (progress) => {
                  console.warn(`Request download status ${progress.state}, downloaded ${progress.processed}`);
                })
                task.on('completed', async (progress) => {
                  console.warn('Request download completed, ' + JSON.stringify(progress));
                  // 该方法需用户管理任务生命周期,任务结束后调用remove释放task对象
                  request.agent.remove(task.tid);
                })
              }).catch((err: BusinessError) => {
                console.error(`Failed to operate a download task, Code: ${err.code}, message: ${err.message}`);
              });
            } catch (err) {
              console.error(`Failed to create a download task, err: ${err}`);
            }
          }
        })
      }
    }
  }
}

下载音频类文件

开发者可以通过调用AudioViewPickersave()接口保存文件并获得用户文件的uri,将此uri作为Config的saveas字段值进行下载。

import { BusinessError, request } from '@kit.BasicServicesKit';
import { picker } from '@kit.CoreFileKit';
import { common } from '@kit.AbilityKit';

@Entry
@Component
struct Index {
  build() {
    Row() {
      Column() {
        Button("下载音频").width("50%").margin({ top: 20 }).height(40).onClick(async () => {
          // 创建文件管理器选项实例。
          const audioSaveOptions = new picker.AudioSaveOptions();
          // 保存文件名(可选)。 默认为空。
          audioSaveOptions.newFileNames = ['xxxx.mp3'];

          let uri: string = '';
          // 请在组件内获取context,确保this.getUIContext().getHostContext()返回结果为UIAbilityContext
          let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
          const audioViewPicker = new picker.AudioViewPicker(context);
          await audioViewPicker.save(audioSaveOptions).then((audioSelectResult: Array<string>) => {
            uri = audioSelectResult[0];
            console.info('AudioViewPicker.save to file succeed and uri is:' + uri);
          }).catch((err: BusinessError) => {
            console.error(`Invoke audioViewPicker.save failed, code is ${err.code}, message is ${err.message}`);
          })
          if (uri != '') {
            let config: request.agent.Config = {
              action: request.agent.Action.DOWNLOAD,
              url: 'https://xxxx/xxxx.mp3',
              // saveas字段是AudioViewPicker保存的文件的uri
              saveas: uri,
              gauge: true,
              // overwrite字段必须为true
              overwrite: true,
              network: request.agent.Network.WIFI,
              // mode字段必须为request.agent.Mode.FOREGROUND
              mode: request.agent.Mode.FOREGROUND,
            };
            try {
              request.agent.create(context, config).then((task: request.agent.Task) => {
                task.start((err: BusinessError) => {
                  if (err) {
                    console.error(`Failed to start the download task, Code: ${err.code}  message: ${err.message}`);
                    return;
                  }
                });
                task.on('progress', async (progress) => {
                  console.warn(`Request download status ${progress.state}, downloaded ${progress.processed}`);
                })
                task.on('completed', async (progress) => {
                  console.warn('Request download completed, ' + JSON.stringify(progress));
                  // 该方法需用户管理任务生命周期,任务结束后调用remove释放task对象
                  request.agent.remove(task.tid);
                })
              }).catch((err: BusinessError) => {
                console.error(`Failed to operate a download task, Code: ${err.code}, message: ${err.message}`);
              });
            } catch (err) {
              console.error(`Failed to create a download task, err: ${err}`);
            }
          }
        })
      }
    }
  }
}

下载图片或视频类文件

开发者可以通过调用PhotoAccessHelpercreateAsset()接口创建媒体文件并获得用户文件的uri,将此uri作为Config的saveas字段值进行下载。

需要权限:ohos.permission.WRITE_IMAGEVIDEO

权限ohos.permission.WRITE_IMAGEVIDEOsystem_basic级别的受限开放权限,normal等级的应用需要将自身的APL等级声明为system_basic及以上。授权方式为user_grant,需要向用户申请授权

import { BusinessError, request } from '@kit.BasicServicesKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';

import { bundleManager } from '@kit.AbilityKit';
import { abilityAccessCtrl, Context, PermissionRequestResult, common } from '@kit.AbilityKit';

@Entry
@Component
struct Index {
  build() {
    Row() {
      Column() {
        Button("下载图片").width("50%").margin({ top: 20 }).height(40).onClick(async () => {
          let bundleFlags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION|
          bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_METADATA;
          // 获取应用程序的accessTokenID。
          let tokenID = -1;
          try {
            await bundleManager.getBundleInfoForSelf(bundleFlags).then((data) => {
              console.info(`/Request getBundleInfoForSelf successfully. Data: ${JSON.stringify(data)}`);
              tokenID = data.appInfo.accessTokenId;
            }).catch((err: BusinessError) => {
              console.error(`GetBundleInfoForSelf failed. Cause: ${err.message}`);
            });
          } catch (err) {
            let message = (err as BusinessError).message;
            console.error('GetBundleInfoForSelf failed: %{public}s', message);
          }
          let context: Context = this.getUIContext().getHostContext() as common.UIAbilityContext;

          let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
          let grant = true;
          // 校验应用是否授予权限。使用Promise异步回调。
          await atManager.checkAccessToken(tokenID, 'ohos.permission.WRITE_IMAGEVIDEO')
            .then((data: abilityAccessCtrl.GrantStatus) => {
              console.log(`/Request checkAccessToken success, data->${JSON.stringify(data)}`);
              if (data != abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
                grant = false;
              }
            })
            .catch((err: BusinessError) => {
              console.error(`GheckAccessToken fail, err->${JSON.stringify(err)}`);
            });

          if (!grant) {
            // 用于UIAbility拉起弹框请求用户授权。使用callback异步回调。
            await atManager.requestPermissionsFromUser(context, ['ohos.permission.WRITE_IMAGEVIDEO'])
              .then((data: PermissionRequestResult) => {
                console.info('/Request grant:' + JSON.stringify(data));
                console.info('/Request grant permissions:' + data.permissions);
                console.info('/Request grant authResults:' + data.authResults);
                console.info('/Request grant dialogShownResults:' + data.dialogShownResults);
              }).catch((err: BusinessError) => {
                console.error('Grant error:' + JSON.stringify(err));
              });
          }

          try {
            let photoType: photoAccessHelper.PhotoType = photoAccessHelper.PhotoType.IMAGE;
            let extension: string = 'jpg';
            let options: photoAccessHelper.CreateOptions = {
              title: 'xxxx'
            }
            // 获取相册管理模块的实例,用于访问和修改相册中的媒体文件。
            let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
            // 指定文件类型、后缀和创建选项,创建图片或视频资源,以Promise方式返回结果。
            let uri: string = await phAccessHelper.createAsset(photoType, extension, options);
            console.info('/Request createAsset uri' + uri);
            console.info('/Request createAsset successfully');

            let config: request.agent.Config = {
              action: request.agent.Action.DOWNLOAD,
              url: 'https://xxxx/xxxx.jpg',
              // saveas字段是PhotoAccessHelper保存的文件的uri
              saveas: uri,
              gauge: true,
              // overwrite字段必须为true
              overwrite: true,
              network: request.agent.Network.WIFI,
              // mode字段必须为request.agent.Mode.FOREGROUND
              mode: request.agent.Mode.FOREGROUND,
            };
            request.agent.create(context, config).then((task: request.agent.Task) => {
              task.start((err: BusinessError) => {
                if (err) {
                  console.error(`Failed to start the download task, Code: ${err.code}  message: ${err.message}`);
                  return;
                }
              });
              task.on('progress', async (progress) => {
                console.warn(`Request download status ${progress.state}, downloaded ${progress.processed}`);
              })
              task.on('completed', async (progress) => {
                console.warn('Request download completed, ' + JSON.stringify(progress));
                //该方法需用户管理任务生命周期,任务结束后调用remove释放task对象
                request.agent.remove(task.tid);
              })
            }).catch((err: BusinessError) => {
              console.error(`Failed to operate a download task, Code: ${err.code}, message: ${err.message}`);
            });
          } catch (err) {
            console.error(`Failed to create a download task, err: ${err}`);
          }
        })
      }
    }
  }
}

添加网络配置

HTTP拦截

开发者可以通过设置配置文件实现HTTP拦截功能,上传下载模块在应用配置禁用HTTP后,无法创建明文HTTP传输的上传下载任务。配置文件在APP中的路径是:src/main/resources/base/profile/network_config.json。请参考网络管理模块配置文件配置参数

参考配置文件如下:

{
  "network-security-config": {
    "base-config": {
      "cleartextTrafficPermitted": true, 
      "trust-anchors": [
        {
          "certificates": "/etc/security/certificates"
        }
      ]
    },
    "domain-config": [
      {
        "cleartextTrafficPermitted": true,
        "domains": [
          {
            "include-subdomains": true,
            "name": "*.example.com"
          }
        ],
      }
    ]
  }
}

你可能感兴趣的鸿蒙文章

harmony 鸿蒙上传下载

0  赞