HarmonyOS Next 系列之从手机选择图片或拍照上传功能实现(五)

news2024/10/6 14:25:44

系列文章目录

HarmonyOS Next 系列之省市区弹窗选择器实现(一)
HarmonyOS Next 系列之验证码输入组件实现(二)
HarmonyOS Next 系列之底部标签栏TabBar实现(三)
HarmonyOS Next 系列之HTTP请求封装和Token持久化存储(四)
HarmonyOS Next 系列之从手机选择图片或拍照上传功能实现(五)


文章目录

  • 系列文章目录
  • 前言
  • 一、实现步骤总结
  • 二、代码实现
    • 1.媒体读写权限检查和申请
    • 2.从手机存储选择图片或拍照
    • 3.复制图片到缓存目录下
    • 4. 接口请求上传图片
  • 三、完整代码
    • 页面调用:


前言

HarmonyOS Next(基于API11)实现从手机选择图片或拍照上传功能,常用于头像上传等操作


一、实现步骤总结

1、媒体读写权限检查和申请
2、从手机存储选择图片或拍照
3、把图片复制到缓存目录
4、接口请求上传图片

分析说明:
图片上传使用API request.uploadFile 而该api上传文件的本地路径只支持internal协议

在这里插入图片描述

所以选择完图片/或拍照后需要把图片从内部存储复制到cache目录下,该操作需要外部存储设备媒体读写权限,且是用户级别的权限,因此每次复制图片前需要检查权限如果没权限需弹窗口让用户授权,最后在通过该api实现上传

在这里插入图片描述

二、代码实现

1.媒体读写权限检查和申请

(1)检查权限

工具类文件:

import bundleManager from '@ohos.bundle.bundleManager';
import abilityAccessCtrl, { Context, Permissions } from '@ohos.abilityAccessCtrl';

//校验应用是否授予权限
//@params permissions:权限名称数组
//@return permissionabilityAccessCtrl:权限名称
async function checkAccessToken(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> {
  let atManager = abilityAccessCtrl.createAtManager();
  let grantStatus: abilityAccessCtrl.GrantStatus = 0;

  // 获取应用程序的accessTokenID
  let tokenId: number = 0;
  try {
    let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
    let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;
    tokenId = appInfo.accessTokenId;
  } catch (err) {
    console.error(`getBundleInfoForSelf failed, code is ${err.code}, message is ${err.message}`);
  }

  // 校验应用是否被授予权限
  try {
    grantStatus = await atManager.checkAccessToken(tokenId, permission);
  } catch (err) {
    console.error(`checkAccessToken failed, code is ${err.code}, message is ${err.message}`);
  }

  return grantStatus;
}


//检查用户权限
//@params permissions:权限名称数组
export  async function checkPermissions(permissions: Permissions): Promise<boolean> {
  try {
    let grantStatus: abilityAccessCtrl.GrantStatus = await checkAccessToken(permissions);
    return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED
  }
  catch (e) {
    return Promise.reject(e)
  }
}

调用:

      const READ_MEDIA_PERMISSION: Permissions = 'ohos.permission.READ_MEDIA' //媒体读取权限
      const WRITE_MEDIA_PERMISSION: Permissions = 'ohos.permission.WRITE_MEDIA' //媒体写入权限
      let permissionList: Permissions[] = []; //需要申请选项列表
      let readPermission = await checkPermissions(READ_MEDIA_PERMISSION)//检查是否有媒体读取权限
      !readPermission && permissionList.push(READ_MEDIA_PERMISSION)
      let writePermission = await checkPermissions(WRITE_MEDIA_PERMISSION)//检查是否有媒体写入权限
      !writePermission && permissionList.push(READ_MEDIA_PERMISSION)

(2)申请权限
工具类文件:

import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
import common from '@ohos.app.ability.common'

interface rejectObj {
  code: number
  message: string
}
/**
 * 申请权限
 * @params context:AblitiyContext
 * @params permissions:权限名称数组
 * @returns  Promise<boolean>:是否授权成功
 */
export async function applyPermission(context: common.UIAbilityContext, permissions: Array<Permissions>): Promise<boolean> {
  let atManager = abilityAccessCtrl.createAtManager();
  return new Promise((resolve: (res: boolean) => void, reject: (e: rejectObj) => void) => {
    atManager.requestPermissionsFromUser(context, permissions).then((data) => {
      let grantStatus: Array<number> = data.authResults;
      resolve(grantStatus.every(item => item === 0))
    }).catch((err: rejectObj) => {
      reject(err)
    })

  })
}

调用:

       private context = getContext(this) as common.UIAbilityContext; //UIAbilityContext
       .....
       .....
       .....
      //申请权限
        let res: boolean = await applyPermission(this.context, permissionList)
        if (!res) {//用户未同意授权
          AlertDialog.show({
            title: "提示",
            message: "无权限读写用户外部存储中的媒体文件信息,请前往系统设置开启",
            alignment: DialogAlignment.Center,
            secondaryButton: {
              value: '关闭',
              action: () => {
              }
            }
          })
        }

2.从手机存储选择图片或拍照

(1)从手机存储选择图片

    import picker from '@ohos.file.picker';
    ....
    ....

       //从相册选择
        let PhotoSelectOptions = new picker.PhotoSelectOptions();
        PhotoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;
        PhotoSelectOptions.maxSelectNumber = 1;
        let photoPicker = new picker.PhotoViewPicker();
        photoPicker.select(PhotoSelectOptions).then(async (PhotoSelectResult) => {
            if (PhotoSelectResult.photoUris.length) {
              console.log(`图片本地路径:${PhotoSelectResult.photoUris[0]}`)
            } 
        })

(2)拍照

    import camera from '@ohos.multimedia.camera';
    import camerapicker from '@ohos.multimedia.cameraPicker';
    import { BusinessError } from '@ohos.base';
    ....
    ....

      try{
         let pickerProfile: camerapicker.PickerProfile = {
            cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK
          };
          let pickerResult: camerapicker.PickerResult = await camerapicker.pick(this.context,
            [camerapicker.PickerMediaType.PHOTO, camerapicker.PickerMediaType.PHOTO], pickerProfile);
        } catch (error) {
          let err = error as BusinessError;
          console.error(`the pick call failed. error code: ${err.code}`);
       }   

3.复制图片到缓存目录下

默认复制图片到缓存目录cache根路径下,移动后文件名前面加上当前时间戳区分:timestamep+原name.格式

import fs from '@ohos.file.fs';

/**
 * 复制文件到缓存目录下
 * @param path :文件路径
 * @param context :Context
 * @returns Promise<string> 移动后文件路径
 */
export async function copyFileToCache(path: string,context:Context): Promise<string> {
  try {

    let file =  fs.openSync(path, fs.OpenMode.READ_WRITE)
    if (file) {
      let fileDir: string = `${context.cacheDir}` //临时文件目录
      //时间戳生成随机文件名
      let newPath: string =  `${new Date().getTime()}_${path.split("/")[path.split("/").length-1]}`
      let targetPath: string = `${fileDir}/${newPath}`
      fs.copyFileSync(file.fd, targetPath)
      return  newPath
    }
    else {
      return ''
    }

  } catch (e) {
    return Promise.resolve('')
  }
}

4. 接口请求上传图片

  //开始上传图片 path:图片路径后缀(图片名称)
  async uploadImage(path: string) {
    let uri=`internal://cache/${path}` //上传图片全路径
    let uploadConfig: request.UploadConfig = {
      url:"http://xxxxxxx",
      header:{},
      method: "POST",
      files: [{ filename: path, name: "file", uri, type: path.split('.')[path.split('.').length-1] }],
      data: [],
    };
    try {
      let uploadTask:request.UploadTask=await request.uploadFile(this.context, uploadConfig)
      //上传中回调
      uploadTask.on('progress', (size,total) => {
        console.log(size.toString(),total.toString(),'上传进度')
      })
      //上传完成回调
      uploadTask.on('complete', (taskStates: request.TaskState[]) => {
        console.info("upOnComplete complete taskState:" + JSON.stringify(taskStates));
      })
      //上传失败回调
      uploadTask.on('fail', (taskStates: request.TaskState[]) => {
        console.info("upOnComplete fail taskState:" + JSON.stringify(taskStates));
      })
    }catch (e){
      console.log( JSON.stringify(e),'e')
    }

  }

需要注意的是我们在复制图片步骤中通过context.cacheDir获取到的缓存目录路径如下所示:

"path":"/data/storage/el2/base/haps/entry/cache/1717854801890_IMG_20240603_170235.jpg"

需转换成internal协议路径,
前面 “/data/storage/el2/base/haps/entry/cache"实际等价于"internal://cache”
所以在上传接口拼接uri参数时候只需要知道图片名称+格式即可,最终上传参数拼接后路径为internal://cache/1717854801890_IMG_20240603_170235.jpg


三、完整代码

完整代码将封装一个完整的组件,自定义底部弹窗菜单选择拍照或从手机相册选择,选完自动上传。
在这里插入图片描述

代码目录结构
在这里插入图片描述

utils/index.ets(工具类):


import fs from '@ohos.file.fs';
import bundleManager from '@ohos.bundle.bundleManager';
import abilityAccessCtrl, { Context, Permissions } from '@ohos.abilityAccessCtrl';
import common from '@ohos.app.ability.common'

/**
 * 复制文件到缓存目录下
 * @param path :文件路径
 * @param context :Context
 * @returns Promise<string> 移动后文件路径
 */
export async function copyFileToCache(path: string,context:Context): Promise<string> {
  try {

    let file =  fs.openSync(path, fs.OpenMode.READ_WRITE)
    if (file) {
      let fileDir: string = `${context.cacheDir}` //临时文件目录
      //时间戳生成随机文件名
      let newPath: string =  `${new Date().getTime()}_${path.split("/")[path.split("/").length-1]}`
      let targetPath: string = `${fileDir}/${newPath}`
      fs.copyFileSync(file.fd, targetPath)
      return  newPath
    }
    else {
      return ''
    }

  } catch (e) {
    return Promise.resolve('')
  }
}

//校验应用是否授予权限
//@params permissions:权限名称数组
//@return permissionabilityAccessCtrl:权限名称
async function checkAccessToken(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> {
  let atManager = abilityAccessCtrl.createAtManager();
  let grantStatus: abilityAccessCtrl.GrantStatus = 0;

  // 获取应用程序的accessTokenID
  let tokenId: number = 0;
  try {
    let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
    let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;
    tokenId = appInfo.accessTokenId;
  } catch (err) {
    console.error(`getBundleInfoForSelf failed, code is ${err.code}, message is ${err.message}`);
  }

  // 校验应用是否被授予权限
  try {
    grantStatus = await atManager.checkAccessToken(tokenId, permission);
  } catch (err) {
    console.error(`checkAccessToken failed, code is ${err.code}, message is ${err.message}`);
  }

  return grantStatus;
}


//检查用户权限
//@params permissions:权限名称数组
export  async function checkPermissions(permissions: Permissions): Promise<boolean> {
  try {
    let grantStatus: abilityAccessCtrl.GrantStatus = await checkAccessToken(permissions);
    return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED
  }
  catch (e) {
    return Promise.reject(e)
  }
}

interface rejectObj {
  code: number
  message: string
}
/**
 * 申请权限
 * @params context:AblitiyContext
 * @params permissions:权限名称数组
 * @returns  Promise<boolean>:是否授权成功
 */
export async function applyPermission(context: common.UIAbilityContext, permissions: Array<Permissions>): Promise<boolean> {
  let atManager = abilityAccessCtrl.createAtManager();
  return new Promise((resolve: (res: boolean) => void, reject: (e: rejectObj) => void) => {
    atManager.requestPermissionsFromUser(context, permissions).then((data) => {
      let grantStatus: Array<number> = data.authResults;
      resolve(grantStatus.every(item => item === 0))
    }).catch((err: rejectObj) => {
      reject(err)
    })

  })
}

ImageUploadDialog.ets(图片上传弹窗菜单选择组件):

import picker from '@ohos.file.picker';
import { checkPermissions, applyPermission, copyFileToCache } from '../../utils/index'
import { request } from '@kit.BasicServicesKit';
import { Permissions } from '@ohos.abilityAccessCtrl';
import camera from '@ohos.multimedia.camera';
import camerapicker from '@ohos.multimedia.cameraPicker';
import { BusinessError } from '@ohos.base';
import { common } from '@kit.AbilityKit';

@Extend(Text)
function custText() {
  .width('100%')
  .height('48')    
  .fontColor('#39364D')
  .textAlign(TextAlign.Center)
}

@CustomDialog
export default struct ImageUploadDialog {
  dialogController: CustomDialogController
  @Prop uploadURL:string='';//上传接口地址
  private context = getContext(this) as common.UIAbilityContext; //UIAbilityContext
  private success:(res: request.TaskState[])=>void=()=>{}//上传成功回调
  private fail:(res: request.TaskState[])=>void=()=>{} //上传失败回调

  //检查权限
  async checkAppPermission(): Promise<boolean> {
    try {
      const READ_MEDIA_PERMISSION: Permissions = 'ohos.permission.READ_MEDIA' //媒体读取权限
      const WRITE_MEDIA_PERMISSION: Permissions = 'ohos.permission.WRITE_MEDIA' //媒体写入权限
      let permissionList: Permissions[] = []; //需要申请选项列表
      let readPermission = await checkPermissions(READ_MEDIA_PERMISSION)//检查是否有媒体读取权限
      !readPermission && permissionList.push(READ_MEDIA_PERMISSION)
      let writePermission = await checkPermissions(WRITE_MEDIA_PERMISSION)//检查是否有媒体写入权限
      !writePermission && permissionList.push(READ_MEDIA_PERMISSION)

      if (permissionList.length) {
         //申请权限
        let res: boolean = await applyPermission(this.context, permissionList)
        if (!res) {//用户未同意授权
          AlertDialog.show({
            title: "提示",
            message: "无权限读写用户外部存储中的媒体文件信息,请前往系统设置开启",
            alignment: DialogAlignment.Center,
            secondaryButton: {
              value: '关闭',
              action: () => {
              }
            }
          })
        }
        return res
      }
      return true

    }

    catch (e) {
      return Promise.reject(e)
    }
  }

  //开始上传图片 path:图片路径后缀(图片名称)
  async uploadImage(path: string) {
    console.log(path, 'path')
    let uri=`internal://cache/${path}` //上传图片全路径
    let uploadConfig: request.UploadConfig = {
      url:this.uploadURL,
      header:{},
      method: "POST",
      files: [{ filename: path, name: "file", uri, type: path.split('.')[path.split('.').length-1] }],
      data: [],
    };
    try {
      let uploadTask:request.UploadTask=await request.uploadFile(this.context, uploadConfig)
      //上传中回调
      uploadTask.on('progress', (size,total) => {
        console.log(size.toString(),total.toString(),'上传进度')
      })
      //上传完成回调
      uploadTask.on('complete', (taskStates: request.TaskState[]) => {
        console.info("upOnComplete complete taskState:" + JSON.stringify(taskStates));
        if(taskStates&&taskStates.length&& taskStates[0].responseCode===0){
          this.success&&this.success(taskStates)
        }
      })
      //上传失败回调
      uploadTask.on('fail', (taskStates: request.TaskState[]) => {
        console.info("upOnComplete fail taskState:" + JSON.stringify(taskStates));
        this.fail&&this.fail(taskStates)
      })
    }catch (e){
      console.log( JSON.stringify(e),'e')
    }

  }

  build() {
    Column() {
      //拍照
      Text('拍照').custText().onClick(async()=>{
        //检查是否有读写外部媒体权限
        let res: boolean = await this.checkAppPermission()
        //无权限返回
        if (!res) return
        try {
          let pickerProfile: camerapicker.PickerProfile = {
            cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK
          };
          let pickerResult: camerapicker.PickerResult = await camerapicker.pick(this.context,
            [camerapicker.PickerMediaType.PHOTO, camerapicker.PickerMediaType.PHOTO], pickerProfile);
          if(pickerResult?.resultUri){
            //关闭弹窗
            this.dialogController.close()
            //复制图片到缓存目录(缓存目录才有读写权限)
            let filePath = await copyFileToCache(pickerResult.resultUri, this.context)
            if (filePath) {
              //上传头像并设置
              this.uploadImage(filePath)
            }

          }
        } catch (error) {
          let err = error as BusinessError;
          console.error(`the pick call failed. error code: ${err.code}`);
        }

      })
      Divider().color('#F7F9FA').width('100%').strokeWidth(1)
      //从手机相册选择
      Text('从手机相册选择').custText().onClick(async () => {
        //检查是否有读写外部媒体权限
        let res: boolean = await this.checkAppPermission()
        //无权限返回
        if (!res) return
        //关闭弹窗
        this.dialogController.close()
        //从相册选择
        let PhotoSelectOptions = new picker.PhotoSelectOptions();
        PhotoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;
        PhotoSelectOptions.maxSelectNumber = 1;
        let photoPicker = new picker.PhotoViewPicker();
        photoPicker.select(PhotoSelectOptions).then(async (PhotoSelectResult) => {
          if (PhotoSelectResult.photoUris.length) {
            //复制图片到缓存目录(缓存目录才有读写权限)
            let filePath = await copyFileToCache(PhotoSelectResult.photoUris[0],this.context)
            if (filePath) {
              this.uploadImage(filePath)
            }
          }
        })
      })
      Button('取消', { type: ButtonType.Capsule })
        .backgroundColor('#F7F7F7')
        .fontSize('16fp')
        .fontColor('#333333')
        .width('100%')
        .margin({ top: '30' })
        .onClick(() => {
          this.dialogController.close()
        })
    }.width('100%').padding({ left: '16', top: '11', right: '16', bottom: '16' })
    .backgroundColor(Color.White)
    .borderRadius({
      topLeft: '24',
      topRight: '24'
    })
  }
}

组件入参 说明:

uploadURL:上传接口url
success:(res: request.TaskState[])=>void 上传成功回调函数
fail:(res: request.TaskState[])=>void=()=>{} //上传失败回调

成功或失败回调参数说明

 request.TaskState[]: {
  path:string //图片在本地路径
  message:string //上传结果信息
  responseCode //上传结果状态码 0:成功,其他值失败
 }[]

从 request.TaskState字段描述可以看出request.uploadFile无法返回接口返回的数据,这也是最大的坑,期待官方解决,如果需要获取上传成功后返回的url,可以在设计个接口上传完再调用该接口获取图片url,如果像头像设置这种功能也可以把图片上传和头像设置整合成一个接口,上传完也即设置完成。

页面调用:

pages/Index

import ImageUploadDialog from '../components/ImageUploadDialog/ImageUploadDialog'
import { promptAction } from '@kit.ArkUI'

@Entry
@Component
struct Index {
  @State dialogController: CustomDialogController | null = null //选择上传类型弹窗控制器
  aboutToAppear(): void {
   this.dialogController= new CustomDialogController({
     builder: ImageUploadDialog({
       uploadURL: 'http://xxxxxxxxx',//上传地址
       success:e=>{//上传成功回调
         console.log(JSON.stringify(e))
         promptAction.showToast({message:'上传成功'})
       },
       fail:e=>{//上传失败回调
         console.log(JSON.stringify(e))
         promptAction.showToast({message:'上传失败'})
       }
     }),
     alignment: DialogAlignment.Bottom,//弹窗居于底部
     customStyle: true,//自定义样式
    })
  }
  build() {
    Column(){
      Button('上传').onClick(()=>{
          this.dialogController?.open()
      })

    }.width('100%')
  }
}

最后不要忘记添加权限
三个:

  "ohos.permission.INTERNET":网访问权限
 "ohos.permission.READ_MEDIA":外部存储设备媒体读取权限
 "ohos.permission.WRITE_MEDIA":外部存储设备媒体写入权限

module.json5:

 //权限
    requestPermissions: [{
      "name": "ohos.permission.INTERNET",
    },{
      "name": "ohos.permission.READ_MEDIA",
      "reason": "$string:reasonReadWriteMedia",//使用权限原因
      "usedScene": {
        "abilities": [//使用的该权限的EntryAbility名称数组
          "EntryAbility"
        ],
        "when": "inuse"
      }
    },{
      "name": "ohos.permission.WRITE_MEDIA",
      "reason": "$string:reasonReadWriteMedia",
      "usedScene": {
        "abilities": [
          "EntryAbility"
        ],
        "when": "inuse"
      }
    }]

entry\src\main\resources\base\element\string.json

{
  "string": [
 ,{
      "name":"reasonReadWriteMedia",
      "value": "上传头像"
    }
  ]
}

效果:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1839646.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CobaltStrike后渗透进阶篇

0x01 网络钓鱼攻击 钓鱼攻击简介 钓鱼攻击主要通过生成的木马诱使受害者运行后上线&#xff0c;其中木马一般都伪装成正常的程序。与此同时配合钓鱼网站可帮助攻击者模拟真实网站诱骗受害者访问&#xff0c;达到获取账号密码、上线木马等目的。接下来主要介绍后门程序的生成及…

vue-json-viewer组件 copyable失效,页面并不现实copy按钮

<json-viewer :value"props.row.param_detail.query" :expand-depth"10" copyable> </json-viewer> 官方文档中&#xff0c;说明&#xff0c;只要在json-viewer中加入 copyable属性&#xff0c;即可实现copy功能&#xff0c;如下图&#xff1…

基于IDEA的Maven(properties属性配置)

&#xff08;property &#xff1a;财产&#xff09;properties&#xff1a;它的复数。 同样也是基于上篇博客进行学习。&#xff08;具体的全部项目代码和结构可以去查看上篇...&#xff09; <properties><!--当前jdk版本 , 这一步可以完全省略--><maven.com…

Swift开发——简单函数实例

函数是模块化编程的基本单位,将一组完成特定功能的代码“独立”地组成一个执行单位,称为函数。函数的基本结构如下所示: 其中,func为定义函数的关键字;“函数名”是调用函数的入口;每个函数可以有多个参数,即可以有多个“参数标签 参数名称:参数类型”,一般地,各个参…

CSS【详解】样式选择器的优先级(含提升优先级的方法)

数值越大&#xff0c;优先级越高&#xff0c;尽量保持较低的优先级&#xff0c;以便使用更高优先级的选择器重置样式 0级——通配选择器、选择符和逻辑组合伪类。逻辑组合伪类有:not()、:is()和:where等&#xff0c;这些伪类本身并不影响CSS优先级&#xff0c;影响优先级的是括…

【qt5生成软件-can卡-上位机-无法加载ControlCAN.dll错误代码(0xc0150002)等相关问题-WIN11系统-尝试解决】

【qt5生成软件-无法加载ControlCAN.dll&错误代码0xc0150002&#xff1a;-等相关问题-WIN11系统-尝试解决-总结整理】 1.前言2.环境说明3.问题说明4.尝试方法总结&#xff08;1&#xff09;更新支持包c库&#xff08;2&#xff09;更新USB相关驱动&#xff08;3&#xff09;…

valgrind工具的交叉编译及使用

一 概述 valgrind是一款非常好用的工具&#xff0c;用于检测内存泄漏等&#xff0c;这里讲述如何将其交叉编译到arm开发板及如何使用 【C/C 集成内存调试、内存泄漏检测和性能分析的工具 Valgrind 】Linux 下 Valgrind 工具的全面使用指南 - 知乎 (zhihu.com) valgrind: fai…

Word2Vec基本实践

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目…

WPF三方UI库全局应用MessageBox样式(.NET6版本)

一、问题场景 使用HandyControl简写HC 作为基础UI组件库时&#xff0c;希望系统中所有的MessageBox 样式都使用HC的MessageBox&#xff0c;常规操作如下&#xff1a; 在对应的xxxx.cs 顶部使用using 指定特定类的命名空间。 using MessageBox HandyControl.Controls.Message…

Elasticseach RestClient Api

Elasticsearch RestclientApi基础用法 查询 索引库 初始化 添加依赖 <dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId> </dependency>创建链接 package com…

今日分享丨点亮这四个技能,你也可以成为可视化专家

引言 以大数据、人工智能等为代表的新质生产力时代已悄然而至&#xff0c;央企、国企逐步意识到数据资源展示对于经营管理的重要性和紧迫性。数据可视化成为连接用户与数据的桥梁&#xff0c;藉由设计师的巧手&#xff0c;把复杂抽象的数据以基于管理需求&#xff0c;转化为直…

PyTorch -- RNN 快速实践

RNN Layer torch.nn.RNN(input_size,hidden_size,num_layers,batch_first) input_size: 输入的编码维度hidden_size: 隐含层的维数num_layers: 隐含层的层数batch_first: True 指定输入的参数顺序为&#xff1a; x&#xff1a;[batch, seq_len, input_size]h0&#xff1a;[batc…

探究C语言函数栈帧的创建和销毁

引言 在C语言程序中&#xff0c;每当一个函数被调用时&#xff0c;系统都会在栈上为该函数分配一块内存空间&#xff0c;这块内存空间就被称为栈帧。 栈帧中包含了函数执行所需的所有信息&#xff0c;如局部变量、参数、返回地址等。栈帧的创建和销毁是函数调用的核心部分&am…

【华为HCIA数通网络工程师真题-数据通信与网络基础】

文章目录 选择题判断题 选择题 1、在 VRP 平台上&#xff0c;可以通过下面哪种方式访向上条历史命令&#xff1f; 上光标 &#xff08;ctrlU 为自定义快捷键&#xff0c;ctrlP 为显示历史缓存区的前一条命令&#xff0c;左光标为移动光标&#xff09; 2、主机 A &#xff08;1…

TensorRT-常见问题

1、ModelImporter.cpp:779: ERROR: builtin_op_importers.cpp:3608 In function importResize:[8] Assertion failed: scales.is_weights() && "Resize scales must be an initializer!"解决方法&#xff1a;将TensorRT版本升到可以匹配cuda版本的最高版本&a…

多态性(Java)

本篇学习面向对象语言的第三个特性——多态。 目录 1、多态的概念 2、继承多态实现条件 3、重写 4、重新与重载的区别&#xff1a; 5、向上转移和向下转型 5、1向上转型&#xff1a; 5、2 向下转型 1、多态的概念 多态的概念&#xff1a;通俗来说&#xff0c;就是多种形态…

Servlet实践操作

Servlet运行原理 Tomcat 的代码内置了 main 方法&#xff0c;当我们启动 Tomcat 的时候&#xff0c;就是从 Tomcat 的 main 方法开始执行的 被 WebServlet 注解修饰的类会在 Tomcat 启动的时候就被获取并集中管理 Tomcat 通过反射这样的语法机制来创建被 WebServlet 注解修饰…

Day 27:2596. 检查骑士巡视方案

Leetcode 2596. 检查骑士巡视方案 骑士在一张 n x n 的棋盘上巡视。在 **有效 **的巡视方案中&#xff0c;骑士会从棋盘的 左上角 出发&#xff0c;并且访问棋盘上的每个格子 恰好一次 。 给你一个 n x n 的整数矩阵 grid &#xff0c;由范围 [0, n * n - 1] 内的不同整数组成&…

超神级!Markdown最详细教程,程序员的福音

超神级&#xff01;Markdown最详细教程&#xff0c;程序员的福音Markdown最详细教程&#xff0c;关于Markdown的语法和使用就先讲到这里&#xff0c;如果喜欢&#xff0c;请关注“IT技术馆”。馆长会更新​最实用的技术&#xff01;https://mp.weixin.qq.com/s/fNzhLFyYRd3skG-…