用户文件概述
用户文件:文件所有者为登录到该终端设备的用户,包括用户私有的图片、视频、音频、文档等。
用户文件存储位置
内置存储
内置存储,是指用户文件存储在终端设备的内部存储设备(空间)上。内置存储设备无法被移除。内置存储的用户文件主要有:
-
用户特有的文件:这部分文件归属于登录该设备的用户,不同用户登录后,仅可看到该用户自己的文件。
按照这些文件的特征/属性,以及用户/应用的使用习惯,可分为:
-
图片/视频类媒体文件
所具有的特征包括拍摄时间、地点、旋转角度、文件宽高等信息,以媒体文件的形式存储在系统中,通常是以所有文件、相册的形式对外呈现,不会展示其在系统中存储的具体位置。
-
音频类媒体文件
所具有的特征包括所属专辑、音频创作者、持续时间等信息,以媒体文件的形式存储在系统中,通常会以所有文件、专辑、作家等形式对外部呈现,不会展示其在系统中存储的具体位置。
-
其他文件(统称为文档类文件)
以普通文件的形式存储在系统中,该类文件既包括普通的文本文件、压缩文件等,又包括以普通文件形式存储的图片/视频、音频文件,该类文件通常是以目录树的形式对外展示。
-
-
多用户共享的文件:用户可以通过将文件放在共享文件区,实现多个用户之间文件的共享访问。
共享文件区的文件,也是以普通文件的形式存储在系统中,以目录树的形式对外展示。
外置存储
外置存储,是指用户文件存储在外置可插拔设备上(如SD卡、U盘等)。外置存储设备上的文件,和内置存储设备共享区文件一样,可以被所有登录到系统中的用户看到。
外置存储设备具备可插拔属性,因此系统提供了设备插拔事件的监听及挂载功能,用于管理外置存储设备,,该部分功能仅对系统应用开放。
外置存储设备上的文件,全部以普通文件的形式呈现,和内置存储设备上的文档类文件一样,采用目录树的形式对外展示。
用户文件uri介绍
用户文件uri是文件的唯一标识,在对用户文件进行访问与修改等操作时往往都会使用到uri,不建议开发者解析uri中的片段用于业务代码开发,不同类型的uri使用方式将在下文详细介绍。
uri的类型
uri类型可以归纳为文档类uri和媒体文件uri两类
- 文档类uri:由picker拉起文件管理器选择或保存返回,以及通过fileAccess模块获取。具体获取方式参见文档类uri获取方式。
- 媒体文件uri:由picker通过拉起图库选择图片或者视频返回,通过photoAccessHelper模块获取图片或者视频文件的uri,以及通过userFileManager模块获取图片、视频或者音频文件的uri。具体获取方式参见媒体文件uri获取方式。
文档类uri
文档类uri介绍
文档类uri的格式类型为:
'file://docs/storage/Users/currentUser/<relative_path>/test.txt'
其中各个字段表示的含义为:
uri字段 | 说明 |
---|---|
'file://docs/storage/Users/currentUser/' | 文件管理器的根目录。 |
'<relative_path>/' | 文件在根目录下的相对路径。例如:'Download/'和'Documents/'。 |
'test.txt' | 用户文件系统中存储的文件名,支持的文件类型为文件管理器支持的所有类型,以文件管理器为准,例如txt、jpg、mp4和mp3等格式的文件。 |
文档类uri获取方式
-
通过DocumentViewPicker接口选择或保存文件,返回选择或保存的文件uri。
-
通过AudioViewPicker接口选择或保存文件,返回选择或保存的文件uri。
-
通过PhotoViewPicker.save接口保存文件,返回保存的文件uri。
文档类uri的使用方式
normal等级的应用使用此类uri的方式只能通过fs模块进行进一步处理,其他模块使用此uri是会报没有权限的错误。示例代码参见picker中的选择文档类文件和保存文档类文件。
媒体文件uri
媒体文件uri介绍
媒体文件uri的格式类型为:
图片uri格式:
- 'file://media/Photo/<id>/IMG_datetime_0001/displayName.jpg'
视频uri格式:
- 'file://media/Photo/<id>/VID_datetime_0001/displayName.mp4'
音频uri格式:
- 'file://media/Audio/<id>/AUD_datetime_0001/displayName.mp3'
其中各个字段表示的含义为:
uri字段 | 说明 |
---|---|
'file://media' | 表示这个uri是媒体文件。 |
'Photo' | Photo表示这个uri是媒体文件中的图片或者视频类文件。 |
'Audio' | 表示这个uri是媒体文件中的音频类文件。 |
'<id>' | 表示在数据库中多个表中处理后的值,并不是指表中的file_id列,注意请不要使用此id去数据库中查询具体文件。 |
'IMG_datetime_0001' | 表示图片文件在用户文件系统中存储的文件名去掉后缀剩下的部分。 |
'VID_datetime_0001' | 表示视频文件在用户文件系统中存储的文件名去掉后缀剩下的部分。 |
'AUD_datetime_0001' | 表示音频文件在用户文件系统中存储的文件名去掉后缀剩下的部分。 |
媒体文件uri获取方式
-
通过PhotoViewPicker.select接口选择媒体文件,返回选择的媒体文件文件的uri。
-
通过photoAccessHelper模块中的getAssets或createAsset接口获取媒体文件对应文件的uri。
媒体文件uri的使用方式
normal等级的应用使用此类uri可以通过photoAccessHelper模块进行进一步处理。示例代码参见媒体资源使用指导中的指定URI获取图片或视频资源。此接口需要申请相册管理模块读权限'ohos.permission.READ_IMAGEVIDEO',在使用中需要注意应用是否有此权限。
若normal等级的应用不想申请权限也可以通过临时授权的方式使用PhotoViewPicker.select接口得到的uri使用photoAccessHelper.getAssets接口获取对应uri的PhotoAsset对象。这种方式获取的对象可以调用getThumbnail获取缩略图和使用get接口读取PhotoKeys中的部分信息。
以下为PhotoKeys中支持临时授权方式可以读取的信息:
名称 | 值 | 说明 |
---|---|---|
URI | 'uri' | 文件uri。 |
PHOTO_TYPE | 'media_type' | 媒体文件类型。 |
DISPLAY_NAME | 'display_name' | 显示名字。 |
SIZE | 'size' | 文件大小。 |
DATE_ADDED | 'date_added' | 添加日期(添加文件时间距1970年1月1日的秒数值)。 |
DATE_MODIFIED | 'date_modified' | 修改日期(修改文件时间距1970年1月1日的秒数值,修改文件名不会改变此值,当文件内容发生修改时才会更新)。 |
DURATION | 'duration' | 持续时间(单位:毫秒)。 |
WIDTH | 'width' | 图片宽度(单位:像素)。 |
HEIGHT | 'height' | 图片高度(单位:像素)。 |
DATE_TAKEN | 'date_taken' | 拍摄日期(文件拍照时间距1970年1月1日的秒数值)。 |
ORIENTATION | 'orientation' | 图片文件的方向。 |
TITLE | 'title' | 文件标题。 |
下面为通过临时授权方式使用媒体文件uri进行获取缩略图和读取文件部分信息的示例代码:
import { picker } from '@kit.CoreFileKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { dataSharePredicates } from '@kit.ArkData';
// 定义一个uri数组,用于接收PhotoViewPicker选择图片返回的uri
let uris: Array<string> = [];
const context = getContext(this);
// 调用PhotoViewPicker.select选择图片
async function photoPickerGetUri() {
try {
let PhotoSelectOptions = new picker.PhotoSelectOptions();
PhotoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;
PhotoSelectOptions.maxSelectNumber = 1;
let photoPicker = new picker.PhotoViewPicker();
photoPicker.select(PhotoSelectOptions).then((PhotoSelectResult: picker.PhotoSelectResult) => {
console.info('PhotoViewPicker.select successfully, PhotoSelectResult uri: ' + JSON.stringify(PhotoSelectResult));
uris = PhotoSelectResult.photoUris;
}).catch((err: BusinessError) => {
console.error('PhotoViewPicker.select failed with err: ' + JSON.stringify(err));
});
} catch (error) {
let err: BusinessError = error as BusinessError;
console.error('PhotoViewPicker failed with err: ' + JSON.stringify(err));
}
}
async function uriGetAssets() {
try {
let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
let predicates: dataSharePredicates.DataSharePredicates = new dataSharePredicates.DataSharePredicates();
// 配置查询条件,使用PhotoViewPicker选择图片返回的uri进行查询
predicates.equalTo('uri', uris[0]);
let fetchOption: photoAccessHelper.FetchOptions = {
fetchColumns: [photoAccessHelper.PhotoKeys.WIDTH, photoAccessHelper.PhotoKeys.HEIGHT, photoAccessHelper.PhotoKeys.TITLE, photoAccessHelper.PhotoKeys.DURATION],
predicates: predicates
};
let fetchResult: photoAccessHelper.FetchResult<photoAccessHelper.PhotoAsset> = await phAccessHelper.getAssets(fetchOption);
// 得到uri对应的PhotoAsset对象,读取文件的部分信息
const asset: photoAccessHelper.PhotoAsset = await fetchResult.getFirstObject();
console.info('asset displayName: ', asset.displayName);
console.info('asset uri: ', asset.uri);
console.info('asset photoType: ', asset.photoType);
console.info('asset width: ', asset.get(photoAccessHelper.PhotoKeys.WIDTH));
console.info('asset height: ', asset.get(photoAccessHelper.PhotoKeys.HEIGHT));
console.info('asset title: ' + asset.get(photoAccessHelper.PhotoKeys.TITLE));
// 获取缩略图
asset.getThumbnail((err, pixelMap) => {
if (err == undefined) {
console.info('getThumbnail successful ' + JSON.stringify(pixelMap));
} else {
console.error('getThumbnail fail', err);
}
});
} catch (error){
console.error('uriGetAssets failed with err: ' + JSON.stringify(error));
}
}
FileUri开发指导(C/C++)
场景介绍
FileUri提供了关于文件URI的基本操作,对外提供了URI与沙箱路径之间互相转换、远端URI判定、获取URI所在目录路径的URI等接口,方便用户将文件URI与沙箱路径相互转换。
基本概念
结果集:满足使用场景正确的路径或者URI。
约束限制
-
转换或者判断URI类型之前必须保证传入的参数正确有效。
-
为保证数据的准确性,在转换或者判断过程中只允许处理一个对象。
接口说明
接口的详细说明,请参考API参考
接口名称 | 描述 |
---|---|
FileManagement_ErrCode OH_FileUri_GetUriFromPath(const char *path, unsigned int length, char **result) | 通过传入的路径PATH获取到对应的URI。 |
FileManagement_ErrCode OH_FileUri_GetPathFromUri(const char *uri, unsigned int length, char **result) | 通过传入的URI获取到对应的沙箱路径PATH。 |
FileManagement_ErrCode OH_FileUri_GetFullDirectoryUri(const char *uri, unsigned int length, char **result) | 获取所在路径URI,文件获取所在路径URI,如果URI指向目录则获取当前路径URI。 |
bool OH_FileUri_IsValidUri(const char *uri, unsigned int length) | 判断传人的URI的格式是否正确。 |
开发步骤
在CMake脚本中链接动态库
CMakeLists.txt中添加以下lib。
target_link_libraries(sample PUBLIC libohfileuri.so)
添加头文件
#include <filemanagement/file_uri/oh_file_uri.h>
调用OH_FileUri_GetUriFromPath接口,在接口中malloc的内存需要在使用完后释放,因此需要free对应的内存。示例代码如下所示:
#include <cstring>
void OH_FileUri_GetUriFromPathExample() {
char *path = "/data/storage/el2/base/files/test.txt";
unsigned int length = strlen(path);
char *uriResult = NULL;
FileManagement_ErrCode ret = OH_FileUri_GetUriFromPath(path, length ,&uriResult);
if (ret == 0 && uriResult !=NULL) {
printf("pathUri=%s", uriResult); // 应用a获取到的URI为:file://com.example.demo/data/storage/el2/base/files/test.txt
}
if (uriResult != NULL) {
free(uriResult);
}
}
调用OH_FileUri_GetPathFromUri通过URi转成对应的PATH,在接口中malloc的内存需要在使用完后释放,因此需要free对应的内存。示例代码如下所示:
#include <cstring>
void OH_FileUri_GetPathFromUriExample() {
char *uri = "file://com.example.demo/data/storage/el2/base/files/test.txt";
unsigned int length = strlen(uri);
char *pathResult = NULL;
FileManagement_ErrCode ret = OH_FileUri_GetPathFromUri(uri, length, &pathResult);
if (ret == 0 && pathResult != NULL) {
printf("pathResult=%s", pathResult); // PathResult值为:/data/storage/el2/base/files/test.txt
}
if (pathResult != NULL) {
free(pathResult);
}
}
调用OH_FileUri_GetFullDirectoryUri获取URI所在路径的URI,在接口中malloc的内存需要在使用完后释放,因此需要free对应的内存。示例代码如下所示:
#include <cstring>
void OH_FileUri_GetFullDirectoryUriExample() {
char *uri = "file://com.example.demo/data/storage/el2/base/files/test.txt";
unsigned int length = strlen(uri);
char *uriResult = NULL;
FileManagement_ErrCode ret = OH_FileUri_GetFullDirectoryUri(uri, length, &uriResult);
if (ret == 0 && uriResult != NULL) {
printf("pathUri=%s",uriResult);//URI所在路径的URI:file://com.example.demo/data/storage/el2/base/files/
}
if (uriResult != NULL) {
free(uriResult);
}
}
可以调用OH_FileUri_IsValidUri接口进行URI格式验证。 示例代码如下所示:
#include <cstring>
void OH_FileUri_IsValidUriExample() {
char *uri = "file://com.example.demo/data/storage/el2/base/files/test.txt";
unsigned int length = strlen(uri);
bool falgs = OH_FileUri_IsValidUri(uri, length);
printf("The URI is valid? falgs=%d", falgs);
}
获取用户目录环境(C/C++)
场景介绍
Environment提供了获取公共文件用户目录路径的能力,以支持三方应用在公共文件用户目录下进行文件访问操作。
约束限制
- 使用此接口,需确认设备具有以下系统能力:SystemCapability.FileManagement.File.Environment.FolderObtain。
- 此接口仅用作公共沙箱目录路径的获取接口,操作对应的公共目录及其子目录需获取通过弹窗授权方式向用户申请授予对应目录的权限,具体参考访问控制-向用户申请授权
接口说明
接口的详细说明,请参考API参考
接口名称 | 描述 |
---|---|
FileManagement_ErrCode OH_Environment_GetUserDownloadDir (char **result) | 获取用户Download目录沙箱路径。只支持2in1设备 |
FileManagement_ErrCode OH_Environment_GetUserDesktopDir (char **result) | 获取用户Desktop目录沙箱路径。只支持2in1设备 |
FileManagement_ErrCode OH_Environment_GetUserDocumentDir (char **result) | 获取用户Document目录沙箱路径。只支持2in1设备 |
开发步骤
在CMake脚本中链接动态库
CMakeLists.txt中添加以下lib。
target_link_libraries(sample PUBLIC libohenvironment.so)
添加头文件
#include <filemanagement/environment/oh_environment.h>
#include <filemanagement/fileio/oh_fileio.h>
调用OH_Environment_GetUserDownloadDir接口获取用户Download目录沙箱路径,在接口中使用malloc申请的内存需要在使用完后释放因此需要free对应的内存。示例代码如下所示:
void GetUserDownloadDirPathExample() {
char *downloadPath = NULL;
FileManagement_ErrCode ret = OH_Environment_GetUserDownloadDir(&downloadPath);
if (ret == 0) {
printf("Download Path=%s", downloadPath);
free(downloadPath);
} else {
printf("GetDownloadPath failed, error code is %d", ret);
}
}
调用OH_Environment_GetUserDesktopDir接口获取用户Desktop目录沙箱路径,在接口中使用malloc申请的内存需要在使用完后释放因此需要free对应的内存。示例代码如下所示:
void GetUserDesktopDirPathExample() {
char *desktopPath = NULL;
FileManagement_ErrCode ret = OH_Environment_GetUserDesktopDir(&desktopPath);
if (ret == 0) {
printf("Desktop Path=%s", desktopPath);
free(desktopPath);
} else {
printf("GetDesktopPath failed, error code is %d", ret);
}
}
调用OH_Environment_GetUserDocumentDir接口获取用户Document目录沙箱路径,在接口中使用malloc申请的内存需要在使用完后释放因此需要free对应的内存。示例代码如下所示:
void GetUserDocumentDirPathExample() {
char *documentPath = NULL;
FileManagement_ErrCode ret = OH_Environment_GetUserDocumentDir(&documentPath);
if (ret == 0) {
printf("Document Path=%s", documentPath);
free(documentPath);
} else {
printf("GetDocumentPath failed, error code is %d", ret);
}
}
选择与保存用户文件
选择用户文件
用户需要分享文件、保存图片、视频等用户文件时,开发者可以通过系统预置的文件选择器(FilePicker),实现该能力。通过Picker访问相关文件,将拉起对应的应用,引导用户完成界面操作,接口本身无需申请权限。picker获取的uri只具有临时权限,获取持久化权限需要通过FilePicker设置永久授权方式获取。
根据用户文件的常见类型,选择器(FilePicker)分别提供以下选项:
-
PhotoViewPicker:适用于图片或视频类型文件的选择与保存(该接口在后续版本不再演进)。请使用PhotoAccessHelper的PhotoViewPicker来选择图片文件。请使用安全控件创建媒体资源。
-
DocumentViewPicker:适用于文件类型文件的选择与保存。DocumentViewPicker对接的选择资源来自于FilePicker, 负责文件类型的资源管理,文件类型不区分后缀,比如浏览器下载的图片、文档等,都属于文件类型。
-
AudioViewPicker:适用于音频类型文件的选择与保存。AudioViewPicker目前对接的选择资源来自于FilePicker。
选择图片或视频类文件
PhotoViewPicker在后续版本不再演进,请使用PhotoAccessHelper的PhotoViewPicker来选择图片文件。
选择文档类文件
-
导入选择器模块和基础文件API模块。
import { picker } from '@kit.CoreFileKit'; import { fileIo as fs } from '@kit.CoreFileKit'; import { common } from '@kit.AbilityKit'; import { BusinessError } from '@kit.BasicServicesKit';
创建文件类型、文件选择选项实例。
const documentSelectOptions = new picker.DocumentSelectOptions();
// 选择文档的最大数目(可选)
documentSelectOptions.maxSelectNumber = 5;
// 指定选择的文件或者目录路径(可选)
documentSelectOptions.defaultFilePathUri = "file://docs/storage/Users/currentUser/test";
// 选择文件的后缀类型['后缀类型描述|后缀类型'](可选) 若选择项存在多个后缀名,则每一个后缀名之间用英文逗号进行分隔(可选),后缀类型名不能超过100,选择所有文件:'所有文件(*.*)|.*';
documentSelectOptions.fileSuffixFilters = ['图片(.png, .jpg)|.png,.jpg', '文档|.txt', '视频|.mp4', '.pdf'];
//选择是否对指定文件或目录授权,true为授权,当为true时,defaultFilePathUri为必选参数,拉起文管授权界面;false为非授权,拉起常规文管界面(可选)
documentSelectOptions.authMode = true;
创建文件选择器DocumentViewPicker实例。调用select()接口拉起FilePicker应用界面进行文件选择。
let uris: Array<string> = [];
let context = getContext(this) as common.Context; // 请确保 getContext(this) 返回结果为 UIAbilityContext
// 创建文件选择器实例
const documentViewPicker = new picker.DocumentViewPicker(context);
documentViewPicker.select(documentSelectOptions).then((documentSelectResult: Array<string>) => {
//文件选择成功后,返回被选中文档的uri结果集。
uris = documentSelectResult;
console.info('documentViewPicker.select to file succeed and uris are:' + uris);
}).catch((err: BusinessError) => {
console.error(`Invoke documentViewPicker.select failed, code is ${err.code}, message is ${err.message}`);
})
注意
1、使用picker获取的select()返回的uri权限是临时只读权限,待退出应用后台后,获取的临时权限就会失效。
2、如果想要获取持久化权限(仅在2in1设备上生效),请参考文件持久化授权访问。
3、开发者可以根据结果集中uri做进一步的处理。建议定义一个全局变量保存uri。
4、如有获取元数据需求,可以通过基础文件API和文件URI根据uri获取部分文件属性信息,比如文件大小、访问时间、修改时间、文件名、文件路径等。
- 待界面从FilePicker返回后,使用基础文件API的fs.openSync接口通过uri打开这个文件得到文件描述符(fd)。
let uri: string = '';
//这里需要注意接口权限参数是fs.OpenMode.READ_ONLY。
let file = fs.openSync(uri, fs.OpenMode.READ_ONLY);
console.info('file fd: ' + file.fd);
通过fd使用fs.readSync接口读取这个文件内的数据。
let buffer = new ArrayBuffer(4096);
let readLen = fs.readSync(file.fd, buffer);
console.info('readSync data to file succeed and buffer size is:' + readLen);
//读取完成后关闭fd。
fs.closeSync(file);
选择音频类文件
-
导入选择器模块和基础文件API模块。
import { picker } from '@kit.CoreFileKit';
import { fileIo as fs } from '@kit.CoreFileKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';
创建音频类型文件选择选项实例。
说明
目前AudioSelectOptions不支持参数配置,默认可以选择所有类型的用户文件。
const audioSelectOptions = new picker.AudioSelectOptions();
创建音频选择器AudioViewPicker实例。调用select()接口拉起FilePicker应用界面进行文件选择。
let uri: string = '';
// 请确保 getContext(this) 返回结果为 UIAbilityContext
let context = getContext(this) as common.Context;
const audioViewPicker = new picker.AudioViewPicker(context);
audioViewPicker.select(audioSelectOptions).then((audioSelectResult: Array<string>) => {
//文件选择成功后,返回被选中音频的uri结果集。
uri = audioSelectResult[0];
console.info('audioViewPicker.select to file succeed and uri is:' + uri);
}).catch((err: BusinessError) => {
console.error(`Invoke audioViewPicker.select failed, code is ${err.code}, message is ${err.message}`);
})
注意
1、使用picker获取的select()返回的uri权限是临时只读权限,待退出应用后台后,获取的临时权限就会失效。
2、如果想要获取持久化权限(仅在2in1设备上生效),请参考文件持久化授权访问。
3、开发者可以根据结果集中的uri做读取文件数据操作。建议定义一个全局变量保存uri。例如通过基础文件API根据uri拿到音频资源的文件描述符(fd),再配合媒体服务实现音频播放的开发,具体请参考音频播放开发指导。
-
待界面从FilePicker返回后,可以使用基础文件API的fs.openSync接口通过uri打开这个文件得到文件描述符(fd)。
let uri: string = '';
//这里需要注意接口权限参数是fs.OpenMode.READ_ONLY。
let file = fs.openSync(uri, fs.OpenMode.READ_ONLY);
console.info('file fd: ' + file.fd);
通过fd可以使用基础文件API的fs.readSync接口读取这个文件内的数据。
let buffer = new ArrayBuffer(4096);
let readLen = fs.readSync(file.fd, buffer);
console.info('readSync data to file succeed and buffer size is:' + readLen);
//读取完成后关闭fd。
fs.closeSync(file);
保存用户文件
在从网络下载文件到本地、或将已有用户文件另存为新的文件路径等场景下,需要使用FilePicker提供的保存用户文件的能力。picker获取的uri只具有临时权限,获取持久化权限需要通过FilePicker设置永久授权方式获取。
对音频、图片、视频、文档类文件的保存操作类似,均通过调用对应picker的save()接口并传入对应的saveOptions来实现。通过Picker访问相关文件,无需申请权限。
当前所有picker的save接口都是用户可感知的,具体行为是拉起FilePicker, 将文件保存在系统文件管理器管理的特定目录,与图库管理的资源隔离,无法在图库中看到。
如需要在图库中看到所保存的图片、视频资源,请使用用户无感的安全控件创建媒体资源。
保存图片或视频类文件
PhotoViewPicker在后续版本不再演进,请使用安全控件创建媒体资源。
保存文档类文件
-
导入选择器模块和基础文件API模块。
import { picker } from '@kit.CoreFileKit';
import { fileIo as fs } from '@kit.CoreFileKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';
创建文档保存选项实例。
// 创建文件管理器选项实例
const documentSaveOptions = new picker.DocumentSaveOptions();
// 保存文件名(可选)
documentSaveOptions.newFileNames = ["DocumentViewPicker01.txt"];
// 保存文件类型['后缀类型描述|后缀类型'],选择所有文件:'所有文件(*.*)|.*'(可选) ,如果选择项存在多个后缀,默认选择第一个。
documentSaveOptions.fileSuffixChoices = ['文档|.txt', '.pdf'];
创建文件选择器DocumentViewPicker实例。调用save()接口拉起FilePicker界面进行文件保存。
let uris: Array<string> = [];
// 请确保 getContext(this) 返回结果为 UIAbilityContext
let context = getContext(this) as common.Context;
// 创建文件选择器实例。
const documentViewPicker = new picker.DocumentViewPicker(context);
//用户选择目标文件夹,用户选择与文件类型相对应的文件夹,即可完成文件保存操作。保存成功后,返回保存文档的uri。
documentViewPicker.save(documentSaveOptions).then((documentSaveResult: Array<string>) => {
uris = documentSaveResult;
console.info('documentViewPicker.save to file succeed and uris are:' + uris);
}).catch((err: BusinessError) => {
console.error(`Invoke documentViewPicker.save failed, code is ${err.code}, message is ${err.message}`);
})
注意
1、不能在picker的回调里直接使用此uri进行打开文件操作,需要定义一个全局变量保存URI。
2、使用picker的save()接口获取到URI的权限是临时读写权限,待退出应用后台后,获取的临时权限就会失效。
3、如果想要获取持久化权限(仅在2in1设备上生效),请参考文件持久化授权访问。
4、可以通过便捷方式,直接将文件保存到Download目录下。
if (!canIUse('SystemCapability.FileManagement.File.Environment.FolderObtain')) {
console.error('this api is not supported on this device');
return;
}
需要权限
:ohos.permission.FILE_ACCESS_PERSIST,具体参考访问控制-申请应用权限,该权限APL等级为system_basic,APL等级为normal的应用需要通过ACL的方式跨级别申请。
示例:
import { BusinessError } from '@kit.BasicServicesKit';
import { picker } from '@kit.CoreFileKit';
import { fileShare } from '@kit.CoreFileKit';
async function persistPermissionExample() {
try {
let DocumentSelectOptions = new picker.DocumentSelectOptions();
let documentPicker = new picker.DocumentViewPicker();
let uris = await documentPicker.select(DocumentSelectOptions);
let policyInfo: fileShare.PolicyInfo = {
uri: uris[0],
operationMode: fileShare.OperationMode.READ_MODE,
};
let policies: Array<fileShare.PolicyInfo> = [policyInfo];
fileShare.persistPermission(policies).then(() => {
console.info("persistPermission successfully");
}).catch((err: BusinessError<Array<fileShare.PolicyErrorResult>>) => {
console.error("persistPermission failed with error message: " + err.message + ", error code: " + err.code);
if (err.code == 13900001 && err.data) {
for (let i = 0; i < err.data.length; i++) {
console.error("error code : " + JSON.stringify(err.data[i].code));
console.error("error uri : " + JSON.stringify(err.data[i].uri));
console.error("error reason : " + JSON.stringify(err.data[i].message));
}
}
});
} catch (error) {
let err: BusinessError = error as BusinessError;
console.error('persistPermission failed with err: ' + JSON.stringify(err));
}
}
-
待界面从FilePicker返回后,使用基础文件API的fs.openSync接口,通过uri打开这个文件得到文件描述符(fd)。
const uri = ''; //这里需要注意接口权限参数是fs.OpenMode.READ_WRITE。 let file = fs.openSync(uri, fs.OpenMode.READ_WRITE); console.info('file fd: ' + file.fd);
通过fd使用基础文件API的fs.writeSync接口对这个文件进行编辑修改,编辑修改完成后关闭fd。
let writeLen: number = fs.writeSync(file.fd, 'hello, world'); console.info('write data to file succeed and size is:' + writeLen); fs.closeSync(file);
保存音频类文件
-
导入选择器模块和基础文件API模块。
import { picker } from '@kit.CoreFileKit'; import { fileIo as fs } from '@kit.CoreFileKit'; import { BusinessError } from '@kit.BasicServicesKit'; import { common } from '@kit.AbilityKit';
创建音频保存选项实例。
// 创建文件管理器选项实例 const audioSaveOptions = new picker.AudioSaveOptions(); // 保存文件名(可选) audioSaveOptions.newFileNames = ['AudioViewPicker01.mp3'];
创建音频选择器AudioViewPicker实例。调用save()接口拉起FilePicker界面进行文件保存。
let uri: string = ''; // 请确保 getContext(this) 返回结果为 UIAbilityContext let context = getContext(this) as common.Context; const audioViewPicker = new picker.AudioViewPicker(context); //用户选择目标文件夹,用户选择与文件类型相对应的文件夹,即可完成文件保存操作。保存成功后,返回保存文档的uri。 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}`); })
注意
1、不能在picker的回调里直接使用此uri进行打开文件操作,需要定义一个全局变量保存uri。
2、使用picker获取的save()uri权限是临时读写权限,待退出应用后台后,获取的临时权限就会失效。
3、如果想要获取持久化权限(仅在2in1设备上生效),请参考文件持久化授权访问。
4、可以通过便捷方式,直接将文件保存到Download目录下。
-
待界面从FilePicker返回后,可以使用基础文件API的fs.openSync接口,通过uri打开这个文件得到文件描述符(fd)。
//这里需要注意接口权限参数是fileIo.OpenMode.READ_WRITE。 let file = fs.openSync(uri, fs.OpenMode.READ_WRITE); console.info('file fd: ' + file.fd);
通过fd使用基础文件API的fs.writeSync接口对这个文件进行编辑修改,编辑修改完成后关闭fd。
let writeLen = fs.writeSync(file.fd, 'hello, world'); console.info('write data to file succeed and size is:' + writeLen); fs.closeSync(file);
DOWNLOAD模式保存文件
用户在使用save接口时,可以将pickerMode配置为DOWNLOAD模式,该模式下会拉起授权接口,用户确认后会在公共路径download目录下创建用户当前hap包名的文件夹,并通过save接口返回值回传相应的URI,后续用户可以直接将文件保存在该URI下。
-
导入选择器模块和文件管理模块。
import { picker } from '@kit.CoreFileKit'; import { fileIo as fs } from '@kit.CoreFileKit'; import { BusinessError } from '@kit.BasicServicesKit'; import { common } from '@kit.AbilityKit';
创建文件保存选项实例。
// 创建文件管理器选项实例 const documentSaveOptions = new picker.DocumentSaveOptions(); // 配置保存的模式为DOWNLOAD,若配置了DOWNLOAD模式,此时配置的其他documentSaveOptions参数将不会生效。 documentSaveOptions.pickerMode = picker.DocumentPickerMode.DOWNLOAD;
创建文件选择器实例。调用save()接口拉起FilePicker模态窗界面进行文件保存。用户点击同意,即可在download目录下创建对应应用的专属目录,返回该目录的uri。
let uri: string = ''; // 请确保 getContext(this) 返回结果为 UIAbilityContext let context = getContext(this) as common.Context; const documentViewPicker = new picker.DocumentViewPicker(context); const documentSaveOptions = new picker.DocumentSaveOptions(); documentSaveOptions.pickerMode = picker.DocumentPickerMode.DOWNLOAD; documentViewPicker.save(documentSaveOptions ).then((documentSaveResult: Array<string>) => { uri = documentSaveResult[0]; console.info('documentViewPicker.save succeed and uri is:' + uri); }).catch((err: BusinessError) => { console.error(`Invoke documentViewPicker.save failed, code is ${err.code}, message is ${err.message}`); })
授权持久化
场景介绍
应用通过Picker获取临时授权,临时授权在应用退出后或者设备重启后会清除,如果应用重启或者设备重启后需要直接访问之前已访问过的文件,则对文件进行持久化授权。
通过Picker获取临时授权并进行授权持久化
通过Picker选择文件或文件夹进行临时授权,然后应用可以按需通过文件分享接口(ohos.fileshare)进行持久化授权。
-
应用仅临时需要访问公共目录的数据,例如:通讯类应用需要发送用户的文件或者图片。应用调用picker的(select)接口选择需要发送的文件或者图片,此时应用获取到是该文件的临时访问权限,应用重启或者设备重启后,再次访问该文件则仍需使用picker进行文件选则。
-
应用如果需要长期访问某个文件或目录时,可以通过Picker选择文件或文件夹进行临时授权,然后利用persistPermission接口(ohos.fileshare.persistPermission)对授权进行持久化(在授权方同意被持久化的情况下),例如:文档编辑类应用本次编辑完一个用户文件,期望在历史记录中可以直接选中打开,无需再拉起picker进行选择授权。
可使用canIUse接口,确认设备是否具有以下系统能力:SystemCapability.FileManagement.File.Environment.FolderObtain。
if (!canIUse('SystemCapability.FileManagement.File.Environment.FolderObtain')) {
console.error('this api is not supported on this device');
return;
}
需要权限
:ohos.permission.FILE_ACCESS_PERSIST,具体参考访问控制-申请应用权限,该权限APL等级为system_basic,APL等级为normal的应用需要通过ACL的方式跨级别申请。
示例:
import { BusinessError } from '@kit.BasicServicesKit';
import { picker } from '@kit.CoreFileKit';
import { fileShare } from '@kit.CoreFileKit';
async function persistPermissionExample() {
try {
let DocumentSelectOptions = new picker.DocumentSelectOptions();
let documentPicker = new picker.DocumentViewPicker();
let uris = await documentPicker.select(DocumentSelectOptions);
let policyInfo: fileShare.PolicyInfo = {
uri: uris[0],
operationMode: fileShare.OperationMode.READ_MODE,
};
let policies: Array<fileShare.PolicyInfo> = [policyInfo];
fileShare.persistPermission(policies).then(() => {
console.info("persistPermission successfully");
}).catch((err: BusinessError<Array<fileShare.PolicyErrorResult>>) => {
console.error("persistPermission failed with error message: " + err.message + ", error code: " + err.code);
if (err.code == 13900001 && err.data) {
for (let i = 0; i < err.data.length; i++) {
console.error("error code : " + JSON.stringify(err.data[i].code));
console.error("error uri : " + JSON.stringify(err.data[i].uri));
console.error("error reason : " + JSON.stringify(err.data[i].message));
}
}
});
} catch (error) {
let err: BusinessError = error as BusinessError;
console.error('persistPermission failed with err: ' + JSON.stringify(err));
}
}
注意
1、持久化授权文件信息建议应用在本地存储数据,供后续按需激活持久化文件。
2、持久化授权的数据存储在系统的数据库中,应用或者设备重启后需要激活已持久化的授权才可以正常使用激活持久化授权。
3、持久化权限接口(仅在2in1上生效可以使用canIUse接口进行校验能力是否可用),且需要申请对应的权限。
4、应用在卸载时会将之前的授权数据全部清除,重新安装后需要重新授权。
备注
C/C++持久化授权接口说明及开发指南具体参考:OH_FileShare_PersistPermission持久化授权接口。
3.可以通过revokePermission接口(ohos.fileshare.revokePermission)对已持久化的文件取消授权,同时更新应用存储的数据以删除最近访问数据。
需要权限
:ohos.permission.FILE_ACCESS_PERSIST,具体参考访问控制-申请应用权限,该权限APL等级为system_basic,APL等级为normal的应用需要通过ACL的方式跨级别申请。
示例:
import { BusinessError } from '@kit.BasicServicesKit';
import { picker } from '@kit.CoreFileKit';
import { fileShare } from '@kit.CoreFileKit';
async function revokePermissionExample() {
try {
let uri = "file://docs/storage/Users/username/tmp.txt";
let policyInfo: fileShare.PolicyInfo = {
uri: uri,
operationMode: fileShare.OperationMode.READ_MODE,
};
let policies: Array<fileShare.PolicyInfo> = [policyInfo];
fileShare.revokePermission(policies).then(() => {
console.info("revokePermission successfully");
}).catch((err: BusinessError<Array<fileShare.PolicyErrorResult>>) => {
console.error("revokePermission failed with error message: " + err.message + ", error code: " + err.code);
if (err.code == 13900001 && err.data) {
for (let i = 0; i < err.data.length; i++) {
console.error("error code : " + JSON.stringify(err.data[i].code));
console.error("error uri : " + JSON.stringify(err.data[i].uri));
console.error("error reason : " + JSON.stringify(err.data[i].message));
}
}
});
} catch (error) {
let err: BusinessError = error as BusinessError;
console.error('revokePermission failed with err: ' + JSON.stringify(err));
}
}
注意
1、示例中的uri来源自应用存储的持久化数据中。
2、建议按照使用需求去激活对应的持久化权限,不要盲目的全量激活。
3、持久化权限接口(仅在2in1上生效可以使用canIUse接口进行校验能力是否可用),且需要申请对应的权限。
备注
C/C++去持久化授权接口说明及开发指南具体参考:OH_FileShare_RevokePermission去持久化授权接口。
激活已经持久化的权限访问文件或目录
对于应用已经持久化的授权,应用每次启动时实际未加载到内存中,需要应用按需进行手动激活已持久化授权的权限,通过activatePermission接口(ohos.fileshare.activatePermission)对已经持久化授权的权限进行使能操作,否则已经持久化授权的权限仍存在不能使用的情况。
需要权限
:ohos.permission.FILE_ACCESS_PERSIST,具体参考访问控制-申请应用权限,该权限APL等级为system_basic,APL等级为normal的应用需要通过ACL的方式跨级别申请。
示例:
import { BusinessError } from '@kit.BasicServicesKit';
import { picker } from '@kit.CoreFileKit';
import { fileShare } from '@kit.CoreFileKit';
async function activatePermissionExample() {
try {
let uri = "file://docs/storage/Users/username/tmp.txt";
let policyInfo: fileShare.PolicyInfo = {
uri: uri,
operationMode: fileShare.OperationMode.READ_MODE,
};
let policies: Array<fileShare.PolicyInfo> = [policyInfo];
fileShare.activatePermission(policies).then(() => {
console.info("activatePermission successfully");
}).catch((err: BusinessError<Array<fileShare.PolicyErrorResult>>) => {
console.error("activatePermission failed with error message: " + err.message + ", error code: " + err.code);
if (err.code == 13900001 && err.data) {
for (let i = 0; i < err.data.length; i++) {
console.error("error code : " + JSON.stringify(err.data[i].code));
console.error("error uri : " + JSON.stringify(err.data[i].uri));
console.error("error reason : " + JSON.stringify(err.data[i].message));
if (err.data[i].code == fileShare.PolicyErrorCode.PERMISSION_NOT_PERSISTED) {
//可以选择进行持久化后再激活。
}
}
}
});
} catch (error) {
let err: BusinessError = error as BusinessError;
console.error('activatePermission failed with err: ' + JSON.stringify(err));
}
}
注意
1、示例中的uri来源自应用存储的持久化数据中。
2、建议按照使用需求去激活对应的持久化权限,不要盲目的全量激活。
3、如果激活失败显示未持久化的权限可以按照示例进行持久化。
3、持久化权限接口(仅在2in1上生效可以使用canIUse接口进行校验能力是否可用),且需要申请对应的权限。
备注
C/C++持久化授权激活接口说明及开发指南具体参考:OH_FileShare_ActivatePermission持久化授权激活接口。
授权持久化(C/C++)
场景介绍
应用通过Picker获取临时授权,临时授权在应用退出后或者设备重启后会清除,如果应用重启或者设备重启后需要直接访问之前已访问过的文件,则对文件进行持久化授权。FileShare提供了支持基于URI的文件及目录授于持久化权限、权限激活、权限查询等方法。
接口说明
接口的详细介绍请参见API参考。
接口名称 | 描述 |
---|---|
OH_FileShare_PersistPermission(const FileShare_PolicyInfo *policies, unsigned int policyNum, FileShare_PolicyErrorResult **result, unsigned int *resultNum) | 对所选择的多个文件或目录URI持久化授权 |
OH_FileShare_RevokePermission(const FileShare_PolicyInfo *policies, unsigned int policyNum, FileShare_PolicyErrorResult **result, unsigned int *resultNum) | 对所选择的多个文件或目录URI取消持久化授权 |
OH_FileShare_ActivatePermission(const FileShare_PolicyInfo *policies, unsigned int policyNum, FileShare_PolicyErrorResult **result, unsigned int *resultNum) | 使能多个已经永久授权过的文件或目录URI |
OH_FileShare_DeactivatePermission(const FileShare_PolicyInfo *policies, unsigned int policyNum, FileShare_PolicyErrorResult **result, unsigned int *resultNum) | 取消使能授权过的多个文件或目录URI |
OH_FileShare_CheckPersistentPermission(const FileShare_PolicyInfo *policies, unsigned int policyNum, bool **result, unsigned int *resultNum) | 校验所选择的多个文件或目录URI的持久化权限结果 |
OH_FileShare_ReleasePolicyErrorResult(FileShare_PolicyErrorResult *errorResult, unsigned int resultNum) | 释放FileShare_PolicyErrorResult内存 |
约束与限制
-
使用文件分享的相关接口,需确认设备具有以下系统能力:SystemCapability.FileManagement.AppFileService.FolderAuthorization。
-
在调用文件分享的相关接口前,需要申请权限:"ohos.permission.FILE_ACCESS_PERSIST",申请方式请参考访问控制-申请应用权限。
开发步骤
以下步骤描述了如何使用FileShare提供的Native API接口
添加动态链接库
CMakeLists.txt中添加以下lib。
target_link_libraries(sample PUBLIC libohfileshare.so)
头文件
#include <filemanagement/fileshare/oh_file_share.h>
#include <iostream>
创建FileShare_PolicyInfo实例,调用OH_FileShare_PersistPermission接口,设置URI的持久化授权,接口入参policyNum最大上限为500。
static const uint32_t POLICY_NUM = 2;
char strTestPath1[] = "file://com.example.fileshare/data/storage/el2/base/files/test1.txt";
char strTestPath2[] = "file://com.example.fileshare/data/storage/el2/base/files/test2.txt";
FileShare_PolicyInfo policy[POLICY_NUM] = {
{strTestPath1, static_cast<unsigned int>(strlen(strTestPath1)), FileShare_OperationMode::READ_MODE},
{strTestPath2, static_cast<unsigned int>(strlen(strTestPath2)), FileShare_OperationMode::WRITE_MODE}};
FileShare_PolicyErrorResult* result = nullptr;
uint32_t resultNum = 0;
auto ret = OH_FileShare_PersistPermission(policy, POLICY_NUM, &result, &resultNum);
if (ret != ERR_OK) {
if (ret == ERR_EPERM && result != nullptr) {
for(uint32_t i = 0; i < resultNum; i++) {
std::cout << "error uri: " << result[i].uri << std::endl;
std::cout << "error code: " << result[i].code << std::endl;
std::cout << "error message: " << result[i].message << std::endl;
}
}
}
OH_FileShare_ReleasePolicyErrorResult(result, resultNum);
调用OH_FileShare_ActivatePermission接口,激活启用已授权过的URI,接口入参policyNum最大上限为500。
auto ret = OH_FileShare_ActivatePermission(policy, POLICY_NUM, &result, &resultNum);
if (ret != ERR_OK) {
if (ret == ERR_EPERM && result != nullptr) {
for(uint32_t i = 0; i < resultNum; i++) {
std::cout << "error uri: " << result[i].uri << std::endl;
std::cout << "error code: " << result[i].code << std::endl;
std::cout << "error message: " << result[i].message << std::endl;
}
}
}
OH_FileShare_ReleasePolicyErrorResult(result, resultNum);
调用OH_FileShare_DeactivatePermission接口,停止已启用授权过URI的访问权限,接口入参policyNum最大上限为500。
auto ret = OH_FileShare_DeactivatePermission(policy, POLICY_NUM, &result, &resultNum);
if (ret != ERR_OK) {
if (ret == ERR_EPERM && result != nullptr) {
for(uint32_t i = 0; i < resultNum; i++) {
std::cout << "error uri: " << result[i].uri << std::endl;
std::cout << "error code: " << result[i].code << std::endl;
std::cout << "error message: " << result[i].message << std::endl;
}
}
}
OH_FileShare_ReleasePolicyErrorResult(result, resultNum);
调用OH_FileShare_RevokePermission接口,撤销已经授权的URI持久化权限,接口入参policyNum最大上限为500。
auto ret = OH_FileShare_RevokePermission(policy, POLICY_NUM, &result, &resultNum);
if (ret != ERR_OK) {
if (ret == ERR_EPERM && result != nullptr) {
for(uint32_t i = 0; i < resultNum; i++) {
std::cout << "error uri: " << result[i].uri << std::endl;
std::cout << "error code: " << result[i].code << std::endl;
std::cout << "error message: " << result[i].message << std::endl;
}
}
}
OH_FileShare_ReleasePolicyErrorResult(result, resultNum);
调用OH_FileShare_CheckPersistentPermission接口,检查URI持久化权限,接口入参policyNum最大上限为500。
bool *result = nullptr;
auto ret = OH_FileShare_CheckPersistentPermission(policy, POLICY_NUM, &result, &resultNum);
if (result != nullptr && resultNum > 0) {
for(uint32_t i = 0; i < resultNum && resultNum <= POLICY_NUM; i++) {
std::cout << "uri: " << policy[i].uri << std::endl;
std::cout << "result: " << result[i] << std::endl;
}
}
std::cout << "retCode: " << ret << std::endl;
free(result);
获取并使用公共目录
通过 ArkTS 接口获取并访问公共目录
目录环境能力接口(ohos.file.environment)提供获取公共目录路径的能力,支持三方应用在公共文件用户目录下进行文件访问操作。
约束限制
接口说明
接口的详细说明,请参考API参考
接口名称 | 描述 |
---|---|
FileManagement_ErrCode OH_Environment_GetUserDownloadDir (char **result) | 获取用户Download目录沙箱路径。只支持2in1设备 |
FileManagement_ErrCode OH_Environment_GetUserDesktopDir (char **result) | 获取用户Desktop目录沙箱路径。只支持2in1设备 |
FileManagement_ErrCode OH_Environment_GetUserDocumentDir (char **result) | 获取用户Document目录沙箱路径。只支持2in1设备 |
开发步骤
在CMake脚本中链接动态库
CMakeLists.txt中添加以下lib。
- 使用此方式,需确认设备具有以下系统能力:SystemCapability.FileManagement.File.Environment.FolderObtain。
if (!canIUse('SystemCapability.FileManagement.File.Environment.FolderObtain')) { console.error('this api is not supported on this device'); return; }
公共目录获取接口仅用于获取公共目录路径,不对公共目录访问权限进行校验。若需访问公共目录需申请对应的公共目录访问权限。三方应用需要访问公共目录时,需通过弹窗授权向用户申请授予 Download 目录权限、Documents 目录权限或 Desktop 目录权限,具体参考访问控制-向用户申请授权。
"requestPermissions" : [ "ohos.permission.READ_WRITE_DOWNLOAD_DIRECTORY", "ohos.permission.READ_WRITE_DOCUMENTS_DIRECTORY", "ohos.permission.READ_WRITE_DESKTOP_DIRECTORY", ]
示例
-
获取公共目录路径。
import { BusinessError } from '@kit.BasicServicesKit'; import { Environment } from '@kit.CoreFileKit'; function getUserDirExample() { try { const downloadPath = Environment.getUserDownloadDir(); console.info(`success to getUserDownloadDir: ${downloadPath}`); const documentsPath = Environment.getUserDocumentDir(); console.info(`success to getUserDocumentDir: ${documentsPath}`); const desktopPath = Environment.getUserDesktopDir(); console.info(`success to getUserDesktopDir: ${desktopPath}`); } catch (error) { const err: BusinessError = error as BusinessError; console.error(`failed to get user dir, because: ${JSON.stringify(err)}`); } }
以 Download 目录为例,访问 Download 目录下的文件。
import { BusinessError } from '@kit.BasicServicesKit'; import { Environment } from '@kit.CoreFileKit'; import { fileIo as fs } from '@kit.CoreFileKit'; import { common } from '@kit.AbilityKit'; function readUserDownloadDirExample() { // 检查是否具有 READ_WRITE_DOWNLOAD_DIRECTORY 权限,无权限则需要向用户申请授予权限。 try { // 获取 Download 目录 const downloadPath = Environment.getUserDownloadDir(); console.info(`success to getUserDownloadDir: ${downloadPath}`); const context = getContext() as common.UIAbilityContext; const dirPath = context.filesDir; console.info(`success to get filesDir: ${dirPath}`); // 查看 Download 目录下的文件并拷贝到沙箱目录中 let fileList: string[] = fs.listFileSync(downloadPath); fileList.forEach((file, index) => { console.info(`${downloadPath} ${index}: ${file}`); fs.copyFileSync(`${downloadPath}/${file}`, `${dirPath}/${file}`); }); // 查看沙箱目录下对应的文件 fileList = fs.listFileSync(dirPath); fileList.forEach((file, index) => { console.info(`${dirPath} ${index}: ${file}`); }); } catch (error) { const err: BusinessError = error as BusinessError; console.error(`Error code: ${err.code}, message: ${err.message}`); } }
以 Download 目录为例,保存文件到 Download 目录。
import { BusinessError } from '@kit.BasicServicesKit'; import { Environment } from '@kit.CoreFileKit'; import { fileIo as fs } from '@kit.CoreFileKit'; function writeUserDownloadDirExample() { // 检查是否具有 READ_WRITE_DOWNLOAD_DIRECTORY 权限,无权限则需要向用户申请授予权限。 try { // 获取 Download 目录 const downloadPath = Environment.getUserDownloadDir(); console.info(`success to getUserDownloadDir: ${downloadPath}`); // 保存 temp.txt 到 Download 目录下 const file = fs.openSync(`${downloadPath}/temp.txt`, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE); fs.writeSync(file.fd, 'write a message'); fs.closeSync(file); } catch (error) { const err: BusinessError = error as BusinessError; console.error(`Error code: ${err.code}, message: ${err.message}`); } }
通过 C/C++ 接口获取并使用公共目录
除了通过 ArkTS 访问公共目录的方式,也可通过 C/C++ 接口进行目录访问,具体可以参考 Environment。
约束限制
- 使用此接口,需确认设备具有以下系统能力:SystemCapability.FileManagement.File.Environment.FolderObtain。
- 三方应用需要访问公共目录时,需通过弹窗授权向用户申请授予 Download 目录权限、Documents 目录权限或 Desktop 目录权限,具体参考访问控制-向用户申请授权。
接口说明
接口的详细说明,请参考API参考
接口名称 描述 FileManagement_ErrCode OH_Environment_GetUserDownloadDir (char **result) 获取用户Download目录沙箱路径。只支持2in1设备 FileManagement_ErrCode OH_Environment_GetUserDesktopDir (char **result) 获取用户Desktop目录沙箱路径。只支持2in1设备 FileManagement_ErrCode OH_Environment_GetUserDocumentDir (char **result) 获取用户Document目录沙箱路径。只支持2in1设备 开发步骤
在CMake脚本中链接动态库
CMakeLists.txt中添加以下lib。
target_link_libraries(sample PUBLIC libohenvironment.so libhilog_ndk.z.so)
添加头文件
#include <filemanagement/environment/oh_environment.h> #include <filemanagement/fileio/oh_fileio.h> #include <hilog/log.h>
调用 OH_Environment_GetUserDownloadDir 接口获取用户 Download 目录沙箱路径,在接口中使用malloc申请的内存需要在使用完后释放因此需要free对应的内存。示例代码如下所示:
void GetUserDownloadDirExample() { char *downloadPath = nullptr; FileManagement_ErrCode ret = OH_Environment_GetUserDownloadDir(&downloadPath); if (ret == 0) { OH_LOG_INFO(LOG_APP, "Download Path=%{public}s", downloadPath); free(downloadPath); } else { OH_LOG_ERROR(LOG_APP, "GetDownloadPath fail, error code is %{public}d", ret); } }
调用 OH_Environment_GetUserDownloadDir 接口获取用户 Download 目录沙箱路径,并查看 Download 目录下的文件。示例代码如下所示:
void ScanUserDownloadDirPathExample() { // 获取 download 路径 char *downloadPath = nullptr; FileManagement_ErrCode ret = OH_Environment_GetUserDownloadDir(&downloadPath); if (ret == 0) { OH_LOG_INFO(LOG_APP, "Download Path=%{public}s", downloadPath); } else { OH_LOG_ERROR(LOG_APP, "GetDownloadPath fail, error code is %{public}d", ret); return; } // 查看文件夹下的文件 struct dirent **namelist = {nullptr}; int num = scandir(downloadPath, &namelist, nullptr, nullptr); if (num < 0) { free(downloadPath); OH_LOG_ERROR(LOG_APP, "Failed to scan dir"); return; } for (int i = 0; i < num; i++) { OH_LOG_INFO(LOG_APP, "%{public}s", namelist[i]->d_name); } free(downloadPath); free(namelist); }
调用 OH_Environment_GetUserDownloadDir 接口获取用户 Download 目录沙箱路径,并保存 temp.txt 到 Download 目录下。示例代码如下所示:
void WriteUserDownloadDirPathExample() { // 获取 download 路径 char *downloadPath = nullptr; FileManagement_ErrCode ret = OH_Environment_GetUserDownloadDir(&downloadPath); if (ret == 0) { OH_LOG_INFO(LOG_APP, "Download Path=%{public}s", downloadPath); } else { OH_LOG_ERROR(LOG_APP, "GetDownloadPath fail, error code is %{public}d", ret); return; } // 保存文件到 download 目录下 std::string filePath = std::string(downloadPath) + "/temp.txt"; free(downloadPath); std::ofstream outfile; outfile.open(filePath.c_str()); if (!outfile) { OH_LOG_ERROR(LOG_APP, "Failed to open file"); return; } std::string msg = "Write a message"; outfile.write(msg.c_str(), sizeof(msg)); outfile.close(); }