Harmonyos Next------图片上传与下载
图片上传至服务器
描述
从手机相册中选择一张图片,然后上传至服务器
选取图片
在从相册或者拍摄获取的图片之前,需要进行权限申请,其权限为媒体内容读写权限
'ohos.permission.READ_MEDIA' //允许应用读取用户外部存储中的媒体文件信息-用户授权
s'ohos.permission.WRITE_MEDIA' //允许应用读写用户外部存储中的媒体文件信息-用户授权
从相册选择图片
通过picker.PhotoViewPicker()
选择相册内容,在选择之前可以设置选择数量、资源类型等。
例如选取其中一张图片,返回的URI格式如下:
file://media/Photo/2/IMG_1713776063_001/screenshot_20240422_165243.jpg
但此格式并不能直接上传至服务器,需要对其进行拷贝,格式转换等操作,将在下节进行阐述。
c
private async openGallery(onSuccess: (uri: string)=> void, onFailed: (error: string)=>void) {
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) => {
//file://media/Photo/2/IMG_1713776063_001/screenshot_20240422_165243.jpg
if (PhotoSelectResult.photoUris.length > 0) {
onSuccess(PhotoSelectResult.photoUris[0])
}
}).catch((err: BusinessError) => {
LoggerJoy.error('PhotoViewPicker.select failed with err: ' + JSON.stringify(err))
onFailed(err.message)
})
} catch (error) {
let err: BusinessError = error as BusinessError
LoggerJoy.error('PhotoViewPicker failed with err: ' + JSON.stringify(err))
onFailed(err.message)
}
}
通过拍摄获取图片
通过cameraPicker.pick
打开相机页面,如果完成拍照并点击确认,则会返回如上节一样格式的URI
c
private async openCamera(onSuccess: (uri: string)=> void, onFailed: (error: string)=>void){
try {
let pickerProfile: cameraPicker.PickerProfile = {
cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK
}
let pickerResult: cameraPicker.PickerResult = await cameraPicker.pick(
getContext(this),
[cameraPicker.PickerMediaType.PHOTO, cameraPicker.PickerMediaType.VIDEO],
pickerProfile
)
if (pickerResult) {
onSuccess( pickerResult.resultUri)
}
} catch (error) {
let err = error as BusinessError
LoggerJoy.error(`the pick call failed. error code: ${err.code}`)
onFailed(err.message)
}
}
将获取的图片上传至服务器
由于上述获取的文件为file
开头,外部并不能直接进行访问,可以将其拷贝到APP目录下的沙箱文件中。由于本Demo采用的是系统提供的request.uploadFile
,其路径前缀指定为internal://cache/
,所有还需在拷贝之后的新路径前加上此前缀,此前缀对应的是临时目录cacheDir
拷贝文件
拷贝之后的文件存放于应用目录下的沙箱文件中
c
private async copyFileToCache(path: string, context: Context): Promise<string>{
try {
let file = await fs.open(path, fs.OpenMode.READ_WRITE)
if (file){
let dir = context.cacheDir + '/avatar'
if (!fs.accessSync(dir)) {
fs.mkdirSync(dir)
}
let newpath = context.cacheDir + `/avatar/hohem${new Date().getTime()}.jpg`
LoggerJoy.info(`newpath:${newpath}`)
await fs.copyFile(file.fd, newpath)
return newpath
}
return ''
} catch (err){
LoggerJoy.info("applog:open file failed with error message: " + err.message + ", error code: " + err.code)
return ''
}
}
上传图片
在使用request前需要导入对应包
import { BusinessError, request } from '@kit.BasicServicesKit'
拷贝之后的路径格式如下
/data/storage/el2/base/haps/entry/cache/avatar/hohem1713924905931.jpg
然后在其前面添加指定前缀internal://cache/
,由于此前缀对应的便是cacheDir
目录,所以将拷贝之后的路径前面一部分进行省略,最终得到的路径如下
internal://cache/avatar/hohem1713924905931.jpg
若未对路径进行转换,会出现401-the parameters check fails this is fail path
异常错误。
在进行上传时,需根据自己云服务器所配置的接受数据格式进行变化request.UploadConfig
,例如是PUT
还是POST
,是否还需其他头参数,例如id、token等
c
private async uploadFileToCloud(context: Context, uploadUrl: string, path: string, avatar: string, onSuccess: (avatar: string)=> void, onFailed: (error: string) => void){
let newPath = await this.copyFileToCache(path, context)//---/data/storage/el2/base/haps/entry/cache/avatar/hohem1713924905931.jpg
newPath = `internal://cache/${newPath.split("cache/")[1]}` //internal://cache/avatar/hohem1713924905931.jpg
LoggerJoy.info(`newpath:${newPath}`)
let file: Array<request.File> = [
{
name: 'avatarName',
filename: 'avatarFilename',
uri: newPath,
type: 'image'
}
]
let config: request.UploadConfig = {
url: uploadUrl,
method: 'PUT',
files: file,
header: {
'Content-Type': 'application/octet-stream'
},
data: []
}
try {
request.uploadFile(
context,
config
).then((result)=>{
onSuccess(avatar)
}).catch((err: BusinessError)=>{
onFailed(err.message)
})
} catch (error) {
//401-the parameters check fails this is fail path
onFailed((error as BusinessError).message)
}
}
图片下载
下载图片比上传图片简单的多,依旧使用系统提供的request.downloadFile
API完成。
例如存在https://xxxxxxx.com/system/202403/1773228028463067136.jpg
URL图片资源,
为了减少文件名称冗余和唯一性,我们可以只截取最后一部分做为下载之后的图片名称(1773228028463067136.jpg
),然后同样保存到应用目录下的沙箱文件下。
最后调用request.downloadFile
即可完成对应下载功能
c
private downloadImages(context: Context,url: string){
let splits = url.split('/')
let fileName = splits[splits.length - 1]
let basePath = context.cacheDir + '/banner' //:/data/storage/el2/base/haps/entry/cache/banner/1773228028463067136.jpg
this.checkBannerDirExist(basePath) //如果目录不存在,则直接创建目录
let config: request.DownloadConfig = {
url: url,
filePath: `${basePath}/${fileName}`
}
try {
request.downloadFile(context, config, (err: BusinessError, data: request.DownloadTask)=>{
if (err) {
//下载失败
LoggerJoy.info(`write local banner failed:${url}`)
return
}
LoggerJoy.info(`download banner successful:${url}`)
//下载成功
})
} catch (error) {
LoggerJoy.info(`write local banner failed:${(error as BusinessError).message}`)
}
}