鸿蒙存储权限申请(读写外部存储文件)

举报
鱼弦 发表于 2025/09/19 10:02:27 2025/09/19
【摘要】 1. 引言在移动应用开发中,​​文件存储是核心功能之一​​——无论是保存用户上传的图片、下载的文档,还是缓存应用数据,都需要依赖设备的存储系统。鸿蒙(HarmonyOS)作为面向全场景的操作系统,支持多种存储介质(如内部存储、外部SD卡、共享存储目录),但出于安全和隐私考虑,​​应用访问外部存储文件(如用户相册、下载目录)必须显式申请存储权限​​。用户在使用HarmonyOS应用时,常遇到需...


1. 引言

在移动应用开发中,​​文件存储是核心功能之一​​——无论是保存用户上传的图片、下载的文档,还是缓存应用数据,都需要依赖设备的存储系统。鸿蒙(HarmonyOS)作为面向全场景的操作系统,支持多种存储介质(如内部存储、外部SD卡、共享存储目录),但出于安全和隐私考虑,​​应用访问外部存储文件(如用户相册、下载目录)必须显式申请存储权限​​。

用户在使用HarmonyOS应用时,常遇到需要读写外部存储的场景:例如,相册类应用需访问用户照片(外部存储的 Pictures 目录),文档编辑类应用需读写下载目录中的PDF/Word文件,或工具类应用需缓存临时数据到共享存储目录。若应用未正确申请存储权限,将导致 ​​文件读写失败(如返回空数据或报错)、功能不可用(如无法保存编辑后的内容)​​,严重影响用户体验。

​鸿蒙系统通过严格的权限管理机制​​,要求应用在访问外部存储前必须向用户申请授权(如 ohos.permission.READ_MEDIAohos.permission.WRITE_MEDIA),并遵循最小化授权原则(仅申请必要的权限)。本文将深入探讨鸿蒙存储权限申请的核心技术、实现方案及最佳实践,通过 ​​完整的代码示例与流程解析​​ 帮助开发者安全、高效地实现外部存储文件的读写功能。


2. 技术背景

​2.1 鸿蒙存储权限的核心机制​

鸿蒙系统将存储权限分为 ​​精细化分类​​,主要涉及以下关键权限:

  • ohos.permission.READ_MEDIA​:读取外部存储中的媒体文件(如图片、音频、视频);
  • ohos.permission.WRITE_MEDIA​:写入外部存储(如保存图片到相册、下载文件到 Downloads 目录);
  • ohos.permission.MANAGE_EXTERNAL_STORAGE​(慎用):管理所有外部存储(包括非媒体文件),但需满足严格的使用场景(如文件管理器类应用),且用户授权流程更严格。

​权限申请的核心流程​​:

  1. ​声明权限​​:在应用的配置文件(module.json5)中声明需要使用的存储权限;
  2. ​动态申请​​:在运行时通过系统API向用户弹出授权弹窗,用户确认后应用方可访问对应存储目录;
  3. ​权限校验​​:在读写文件前,检查权限是否已授予,避免未授权操作导致崩溃或数据丢失;
  4. ​最小化原则​​:仅申请应用必需的权限(如仅需读取图片则不申请写入权限),减少用户隐私顾虑。

​2.2 鸿蒙存储目录结构​

鸿蒙的外部存储主要分为以下目录(通过 context.getSharedStorageDir()context.getExternalFilesDir() 访问):

  • ​共享存储目录(Shared Storage)​​:如 /storage/emulated/0/(用户可见的“内部存储”),包含 Pictures(相册)、Downloads(下载)、DCIM(相机)等系统目录;
  • ​应用专属存储目录(App-Specific Storage)​​:如 /storage/emulated/0/Android/data/<package_name>/(用户卸载应用时自动删除),无需额外权限即可读写,但仅限本应用使用。

​关键区别​​:

  • 访问共享存储目录(如用户相册)需申请存储权限;
  • 访问应用专属存储目录无需权限,但数据隔离性更强。

​2.3 典型应用场景​

场景类型 需求描述 核心权限需求
相册类应用 读取用户相册中的图片(共享存储的 Pictures 目录),保存编辑后的图片 ohos.permission.READ_MEDIAohos.permission.WRITE_MEDIA
文档编辑类应用 读写下载目录(Downloads)中的PDF/Word文件,或缓存临时草稿到共享存储 ohos.permission.READ_MEDIAohos.permission.WRITE_MEDIA
工具类应用 缓存用户生成的临时文件(如日志、截图)到共享存储的 Documents 目录 ohos.permission.WRITE_MEDIA(写入)或 ohos.permission.READ_MEDIA(读取)
社交类应用 保存用户分享的图片到相册(共享存储),或读取聊天中的媒体附件 ohos.permission.READ_MEDIAohos.permission.WRITE_MEDIA

3. 应用使用场景

​3.1 典型H5应用场景​

  • ​移动端HarmonyOS应用​​:相册编辑APP(如美图工具)、文档管理APP(如PDF阅读器)、工具类APP(如文件扫描器);
  • ​跨设备场景​​:鸿蒙手机与平板协同时,共享存储目录(如 Downloads)的文件需跨设备读写,权限申请需在两台设备上均通过;
  • ​后台服务​​:需要定期清理缓存文件(共享存储的 Cache 目录)的后台任务,需确保有写入权限。

4. 不同场景下的详细代码实现

​4.1 环境准备​

  • ​开发工具​​:DevEco Studio(鸿蒙官方IDE,支持ArkTS/JS开发);
  • ​核心技术​​:
    • @ohos.fileio 模块​​:提供文件读写API(如 readFilewriteFile);
    • @ohos.security.permissions 模块​​:用于权限申请与校验(如 requestPermissionsFromUser);
    • context 对象​​:通过Ability上下文获取存储目录路径(如 getSharedStorageDir);
  • ​关键概念​​:
    • ​权限声明​​:在 module.json5 中配置 requestPermissions 字段;
    • ​动态申请​​:通过 permissions.requestPermissionsFromUser 弹出授权弹窗;
    • ​权限校验​​:使用 permissions.verifySelfPermission 检查权限是否已授予。

​4.2 典型场景1:申请读写共享存储目录权限并保存图片(ArkTS实现)​

​4.2.1 代码实现步骤​

​4.2.1.1 配置权限(module.json5)​

在应用的配置文件中声明所需的存储权限:

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.READ_MEDIA",
        "reason": "用于读取用户相册中的图片"
      },
      {
        "name": "ohos.permission.WRITE_MEDIA",
        "reason": "用于保存编辑后的图片到相册"
      }
    ]
  }
}
​4.2.1.2 核心代码(MainAbility.ets)​
import permissions from '@ohos.security.permissions';
import fileio from '@ohos.fileio';
import promptAction from '@ohos.promptAction';
import { BusinessError } from '@ohos.base';

// 存储权限管理类
export default class StoragePermissionManager {
  private context: common.UIAbilityContext; // Ability上下文

  constructor(context: common.UIAbilityContext) {
    this.context = context;
  }

  // 检查权限是否已授予
  private checkPermission(permission: string): boolean {
    return permissions.verifySelfPermission(this.context, permission)
      .then((result) => {
        return result === permissions.PermissionResult.PERMISSION_GRANTED;
      })
      .catch((error: BusinessError) => {
        console.error(`检查权限 ${permission} 失败:`, error.message);
        return false;
      });
  }

  // 动态申请权限
  private requestPermissions(permissionsList: string[]): Promise<boolean> {
    return permissions.requestPermissionsFromUser(this.context, permissionsList)
      .then((result) => {
        // result: 数组,对应permissionsList中每个权限的申请结果(true=已授予,false=拒绝)
        const allGranted = result.every((granted) => granted);
        if (allGranted) {
          promptAction.showToast({
            message: '存储权限申请成功',
            duration: 2000
          });
        } else {
          promptAction.alert({
            title: '权限提示',
            message: '需要存储权限才能读写文件,请前往设置中开启',
            primaryButton: {
              value: '去设置',
              action: () => {
                // 引导用户跳转到应用权限设置页(需调用系统API,此处简化为提示)
                promptAction.showToast({
                  message: '请手动开启存储权限',
                  duration: 3000
                });
              }
            },
            secondaryButton: {
              value: '取消',
              action: () => {}
            }
          });
        }
        return allGranted;
      })
      .catch((error: BusinessError) => {
        console.error('申请权限失败:', error.message);
        return false;
      });
  }

  // 保存图片到共享存储目录(示例:保存到Downloads目录)
  public async saveImageToSharedStorage(imageData: Uint8Array, fileName: string): Promise<void> {
    // 1. 检查并申请权限
    const hasReadPermission = await this.checkPermission('ohos.permission.READ_MEDIA');
    const hasWritePermission = await this.checkPermission('ohos.permission.WRITE_MEDIA');
    if (!hasReadPermission || !hasWritePermission) {
      const permissionsToRequest = [];
      if (!hasReadPermission) permissionsToRequest.push('ohos.permission.READ_MEDIA');
      if (!hasWritePermission) permissionsToRequest.push('ohos.permission.WRITE_MEDIA');
      const allGranted = await this.requestPermissions(permissionsToRequest);
      if (!allGranted) {
        throw new Error('存储权限未授予,无法保存图片');
      }
    }

    // 2. 获取共享存储目录的路径(如Downloads目录)
    const sharedStorageDir = this.context.getSharedStorageDir('Downloads'); // 实际路径可能为 /storage/emulated/0/Downloads
    if (!sharedStorageDir) {
      throw new Error('获取共享存储目录失败');
    }

    // 3. 拼接文件完整路径(如 /storage/emulated/0/Downloads/my_image.png)
    const filePath = `${sharedStorageDir}/${fileName}`;

    // 4. 写入文件(二进制数据)
    try {
      const fd = fileio.openSync(filePath, fileio.O_RDWR | fileio.O_CREAT | fileio.O_TRUNC, 0o644);
      fileio.writeSync(fd.fd, imageData, 0, imageData.length);
      fileio.closeSync(fd.fd);
      promptAction.showToast({
        message: `图片已保存到: ${filePath}`,
        duration: 2000
      });
    } catch (error: any) {
      console.error('写入文件失败:', error.message);
      throw new Error(`保存图片失败: ${error.message}`);
    }
  }

  // 读取共享存储目录中的图片(示例:读取Downloads目录下的文件)
  public async readImageFromSharedStorage(fileName: string): Promise<Uint8Array> {
    // 1. 检查并申请读取权限
    const hasReadPermission = await this.checkPermission('ohos.permission.READ_MEDIA');
    if (!hasReadPermission) {
      const granted = await this.requestPermissions(['ohos.permission.READ_MEDIA']);
      if (!granted) {
        throw new Error('读取权限未授予,无法读取图片');
      }
    }

    // 2. 获取共享存储目录路径
    const sharedStorageDir = this.context.getSharedStorageDir('Downloads');
    if (!sharedStorageDir) {
      throw new Error('获取共享存储目录失败');
    }

    // 3. 拼接文件路径
    const filePath = `${sharedStorageDir}/${fileName}`;

    // 4. 读取文件
    try {
      const fd = fileio.openSync(filePath, fileio.O_RDONLY);
      const fileInfo = fileio.statSync(fd.fd);
      const buffer = new ArrayBuffer(fileInfo.size);
      const uint8Array = new Uint8Array(buffer);
      fileio.readSync(fd.fd, uint8Array, 0, fileInfo.size);
      fileio.closeSync(fd.fd);
      return uint8Array;
    } catch (error: any) {
      console.error('读取文件失败:', error.message);
      throw new Error(`读取图片失败: ${error.message}`);
    }
  }
}

// 在Ability的生命周期中使用
@Entry
@Component
struct MainAbility {
  @State storageManager: StoragePermissionManager | null = null;

  aboutToAppear() {
    const context = getContext(this) as common.UIAbilityContext;
    this.storageManager = new StoragePermissionManager(context);
  }

  // 示例:保存图片按钮点击事件(模拟用户点击保存)
  saveImage() {
    if (!this.storageManager) return;
    // 模拟图片数据(实际项目中为相机拍摄或相册选择的图片二进制流)
    const mockImageData = new Uint8Array([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]); // PNG文件头
    this.storageManager.saveImageToSharedStorage(mockImageData, 'test_image.png')
      .then(() => {
        console.info('图片保存成功');
      })
      .catch((error: Error) => {
        promptAction.alert({
          title: '保存失败',
          message: error.message,
          primaryButton: { value: '确定' }
        });
      });
  }

  // 示例:读取图片按钮点击事件(模拟用户点击读取)
  readImage() {
    if (!this.storageManager) return;
    this.storageManager.readImageFromSharedStorage('test_image.png')
      .then((imageData) => {
        console.info('图片读取成功,大小:', imageData.length);
        promptAction.showToast({
          message: '图片读取成功',
          duration: 2000
        });
      })
      .catch((error: Error) => {
        promptAction.alert({
          title: '读取失败',
          message: error.message,
          primaryButton: { value: '确定' }
        });
      });
  }

  build() {
    Column() {
      Text('鸿蒙存储权限申请示例')
        .fontSize(24)
        .margin(20)
      Button('保存图片到共享存储')
        .onClick(() => this.saveImage())
        .margin(10)
      Button('读取共享存储中的图片')
        .onClick(() => this.readImage())
        .margin(10)
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

​4.2.2 代码解析​

  • ​权限声明​​:在 module.json5 中声明 ohos.permission.READ_MEDIAohos.permission.WRITE_MEDIA,并向用户说明用途(如“用于读取相册图片”);
  • ​权限校验与申请​​:
    • checkPermission 方法通过 permissions.verifySelfPermission 检查权限是否已授予;
    • requestPermissionsFromUser 方法弹出系统授权弹窗,用户确认后返回各权限的申请结果;
  • ​文件读写逻辑​​:
    • ​保存图片​​:获取共享存储目录(如 Downloads)的路径,拼接文件名(如 test_image.png),通过 fileio.openSync 打开文件(创建或覆盖),写入二进制数据(Uint8Array);
    • ​读取图片​​:同样获取共享存储目录路径,打开文件并读取二进制数据,返回给调用方;
  • ​用户交互​​:通过 promptAction.showToastpromptAction.alert 提示用户权限状态和操作结果(如“保存成功”或“请开启权限”)。

​4.2.3 运行结果​

  • ​首次运行​​:用户点击“保存图片”时,系统弹出授权弹窗请求“存储权限”,用户确认后图片保存到 Downloads/test_image.png,并显示Toast提示;
  • ​未授权场景​​:若用户拒绝权限申请,提示“需要存储权限才能读写文件,请前往设置中开启”;
  • ​读取操作​​:点击“读取图片”时,若权限已授予则显示“图片读取成功”,否则引导用户授权。

​4.3 典型场景2:仅申请读取权限(如相册预览)​

​4.3.1 场景描述​

相册预览类应用仅需读取用户相册中的图片(无需修改或删除),因此只需申请 ohos.permission.READ_MEDIA 权限,减少用户隐私顾虑。

​4.3.2 代码实现(核心逻辑简化)​

(在4.2.1的基础上,移除写入权限相关代码,仅保留 ohos.permission.READ_MEDIA 的申请与图片读取逻辑。)


5. 原理解释

​5.1 存储权限申请的核心工作流程​

  1. ​权限声明​​:开发者在 module.json5 中明确列出需要使用的存储权限(如 READ_MEDIAWRITE_MEDIA),并向用户说明用途;
  2. ​权限校验​​:在读写文件前,通过 permissions.verifySelfPermission 检查权限是否已授予,避免未授权操作;
  3. ​动态申请​​:若权限未授予,通过 permissions.requestPermissionsFromUser 弹出系统授权弹窗,用户可选择“允许”或“拒绝”;
  4. ​结果处理​​:根据用户的选择(授权/拒绝),执行后续操作(如保存文件或提示用户去设置页开启权限);
  5. ​最小化原则​​:仅申请应用必需的权限(如仅需读取则不申请写入),提升用户授权意愿。

​5.2 核心特性总结​

特性 说明 典型应用场景
​精细化权限控制​ 区分读取(READ_MEDIA)和写入(WRITE_MEDIA)权限,避免过度授权 相册预览(仅需读取)、文件编辑(需写入)
​动态申请​ 运行时向用户弹出授权弹窗,实时获取授权结果 所有需要访问外部存储的应用
​最小化原则​ 仅申请必要的权限,减少用户隐私担忧 工具类应用(如仅缓存数据)
​安全性​ 未授权时禁止访问外部存储,防止恶意应用窃取用户数据 所有涉及用户数据的场景
​用户引导​ 权限拒绝时提示用户手动开启(跳转到设置页),提升功能可用性 权限敏感型应用

6. 原理流程图及原理解释

​6.1 存储权限申请的完整流程图​

sequenceDiagram
    participant 用户 as 用户
    participant 应用 as HarmonyOS应用(ArkTS)
    participant 系统 as 鸿蒙系统(权限管理)
    participant 存储 as 外部存储(如Shared Storage)

    用户->>应用: 点击保存/读取文件按钮
    应用->>应用: 检查权限是否已授予(verifySelfPermission)
    alt 权限已授予
      应用->>存储: 执行文件读写操作(如写入图片到Downloads)
      存储-->>应用: 返回操作结果(成功/失败)
      应用->>用户: 提示操作结果(如“保存成功”)
    else 权限未授予
      应用->>系统: 动态申请权限(requestPermissionsFromUser)
      系统->>用户: 弹出授权弹窗(如“是否允许访问相册?”)
      用户->>系统: 选择“允许”或“拒绝”
      系统->>应用: 返回授权结果(true/false)
      alt 用户允许
        应用->>存储: 执行文件读写操作
        存储-->>应用: 返回操作结果
        应用->>用户: 提示成功
      else 用户拒绝
        应用->>用户: 提示去设置页开启权限(或功能不可用)
      end
    end

​6.2 原理解释​

  • ​用户触发​​:用户通过UI操作(如点击“保存图片”)发起文件读写请求;
  • ​权限校验​​:应用优先检查权限是否已授予(避免重复申请),若已授予则直接执行文件操作;
  • ​动态申请​​:若权限未授予,应用通过系统API弹出授权弹窗,用户看到明确的权限用途说明(如“用于保存图片到相册”);
  • ​结果处理​​:根据用户选择(允许/拒绝),应用执行后续逻辑(如保存文件或提示用户手动开启权限);
  • ​安全保障​​:未授权时禁止访问外部存储,确保用户数据隐私不被非法读取。

7. 实际详细应用代码示例(综合案例:文档编辑器)

​7.1 场景描述​

文档编辑类应用(如PDF阅读器)需 ​​读取下载目录中的PDF文件(共享存储)​​,并 ​​保存编辑后的版本到同一目录​​。通过申请 READ_MEDIAWRITE_MEDIA 权限,实现安全的文件读写。

​7.2 代码实现(核心逻辑复用)​

(基于4.2.1的代码,扩展PDF文件的读写逻辑,例如:

// 保存PDF文件(示例:用户编辑后保存)
public async savePdfToDownloads(pdfData: Uint8Array, fileName: string) {
  // ...(复用saveImageToSharedStorage逻辑,仅修改文件名和提示信息)
}

// 读取PDF文件(示例:加载下载目录中的PDF)
public async readPdfFromDownloads(fileName: string): Promise<Uint8Array> {
  // ...(复用readImageFromSharedStorage逻辑,仅修改文件名和提示信息)
}


8. 运行结果

​8.1 基础场景(权限申请与文件操作)​

  • ​首次运行​​:用户点击“保存图片”时,系统弹出授权弹窗,用户确认后图片保存到 Downloads/test_image.png
  • ​未授权场景​​:用户拒绝权限后,提示“需要存储权限才能读写文件,请前往设置中开启”;
  • ​读取操作​​:用户点击“读取图片”时,若权限已授予则显示“图片读取成功”,否则引导授权。

​8.2 文档编辑场景​

  • ​读取PDF​​:用户打开下载目录中的PDF文件时,应用申请 READ_MEDIA 权限并加载文件内容;
  • ​保存PDF​​:用户编辑后保存时,申请 WRITE_MEDIA 权限并覆盖原文件或生成新版本。

9. 测试步骤及详细代码

​9.1 基础功能测试​

  1. ​权限校验​​:卸载应用后重新安装,首次点击“保存图片”时检查是否弹出授权弹窗;
  2. ​文件操作​​:授权后验证图片是否能成功保存到 Downloads 目录,并通过文件管理器查看;
  3. ​拒绝场景​​:用户拒绝权限后,检查是否提示“功能不可用”或引导去设置页。

​9.2 边界测试​

  1. ​无存储设备​​:模拟设备无外部存储(如仅使用内部存储),验证权限申请和文件操作是否适配;
  2. ​大文件读写​​:尝试保存100MB以上的文件,检查是否因权限或存储空间不足导致失败。

10. 部署场景

​10.1 生产环境部署​

  • ​权限配置​​:确保 module.json5 中仅声明必要的存储权限,并提供清晰的用户说明;
  • ​用户引导​​:在权限拒绝时,提供“去设置”按钮(实际项目中调用系统API跳转到应用权限页);
  • ​兼容性测试​​:在不同鸿蒙设备(如手机、平板)上测试存储目录路径和权限行为的差异。

​10.2 适用场景​

  • ​相册/文档类应用​​:需要读写用户相册、下载目录的应用;
  • ​工具类应用​​:缓存临时文件、日志文件到共享存储的应用;
  • ​跨设备同步​​:需要访问共享存储目录以实现多设备数据同步的应用。

11. 疑难解答

​11.1 问题1:权限申请弹窗未弹出​

  • ​可能原因​​:未正确调用 requestPermissionsFromUser,或权限已在 module.json5 中声明但未动态申请;
  • ​解决方案​​:检查代码中是否调用了动态申请方法,并确认 module.json5 中的权限名称拼写正确。

​11.2 问题2:文件写入失败(权限已授予)​

  • ​可能原因​​:存储目录路径错误(如使用了应用专属目录而非共享存储目录)、文件系统权限不足;
  • ​解决方案​​:通过 context.getSharedStorageDir 获取正确的共享存储路径,并检查文件是否被其他应用占用。

​11.3 问题3:用户拒绝权限后无法引导开启​

  • ​可能原因​​:未实现跳转到应用权限设置页的逻辑(如 settings 模块);
  • ​解决方案​​:在拒绝回调中提示用户手动进入“设置→应用→权限管理”开启存储权限(或调用系统API实现跳转)。

12. 未来展望

​12.1 技术趋势​

  • ​统一存储权限模型​​:未来鸿蒙可能进一步简化存储权限分类(如合并 READ_MEDIAWRITE_MEDIA 为单一权限),降低开发者适配成本;
  • ​智能权限推荐​​:系统根据应用行为(如仅读取相册图片)自动推荐最小化权限,提升用户授权意愿;
  • ​跨设备存储同步​​:鸿蒙生态中,手机、平板、智慧屏等设备的共享存储目录权限互通,实现文件无缝访问;
  • ​隐私增强​​:引入“临时权限”机制(如仅在应用前台运行时授权读写),进一步提升用户数据安全性。

​12.2 挑战​

  • ​多设备兼容性​​:不同鸿蒙设备(如手机与平板)的共享存储目录路径或权限行为可能存在差异;
  • ​用户教育​​:部分用户可能拒绝存储权限导致功能受限,需开发者通过UI设计引导用户理解必要性;
  • ​安全与体验平衡​​:严格权限管理可能限制应用功能(如无法自动保存草稿),需找到“安全”与“便捷”的平衡点。

​13. 总结​

鸿蒙存储权限申请通过 ​​原生的 @ohos.security.permissions 模块和精细化权限分类(如 READ_MEDIAWRITE_MEDIA)​​,实现了对外部存储文件的安全访问控制。本文通过 ​​技术背景、应用场景(相册/文档编辑)、代码示例(ArkTS)、原理解释(流程图)、环境准备及疑难解答​​ 的全面解析,揭示了:

  • ​核心原理​​:基于动态申请和最小化授权原则,通过用户交互获取存储权限,保障用户数据隐私;
  • ​最佳实践​​:区分读取与写入权限、检查权限状态后再操作文件、引导用户处理拒绝场景;
  • ​技术扩展​​:未来可能通过统一权限模型和跨设备同步进一步优化体验;
  • ​未来方向​​:随着鸿蒙生态的成熟,存储权限管理将成为应用安全与用户体验的核心能力之一。

掌握存储权限申请技术,开发者能够构建 ​​安全、高效、用户友好​​ 的H5应用,在鸿蒙平台上实现稳定的文件读写功能,满足用户对数据存储与隐私保护的双重需求。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。