【鸿蒙应用ArkTS开发系列】- 选择图片、文件和拍照功能实现

文章目录

  • 前言
  • 创建多媒体Demo工程
  • 创建MediaBean 实体类
  • 创建MediaHelper工具类
  • API标记弃用问题
  • 动态申请多媒体访问权限
  • 实现选择图片显示功能
  • 打包测试

前言

在使用App的时候,我们经常会在一些社交软件中聊天时发一些图片或者文件之类的多媒体文件,那在鸿蒙原生应用中,我们怎么开发这样的功能呢? 本文会给大家对这个功能点进行讲解,我们采用的是拉起系统组件来进行图片、文件的选择,拉起系统相机进行拍照的这样一种实现方式。
在文章开始之前,按照惯例,我们先展示本文Demo效果图:

在这里插入图片描述

下面我们正式开始讲解。

创建多媒体Demo工程

我们使用Empty 模板创建一个Demo工程。
在这里插入图片描述
在这里插入图片描述

创建MediaBean 实体类

在src->main->ets 下面创建bean文件夹,在文件夹下创建MediaBean.ts文件

/*** 多媒体数据类*/
export class MediaBean {/*** 文件名称*/public fileName: string;/*** 文件大小*/public fileSize: number;/*** 文件类型*/public fileType: string;/*** 本地存储地址*/public localUrl: string;
}

创建MediaHelper工具类

在src->main->ets 下面创建helper文件夹,在文件夹下创建MediaHelper.ts文件

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

/*** 多媒体辅助类*/
export class MediaHelper {private readonly TAG: string = 'MediaHelper';private mContext: common.Context;constructor(context: common.Context) {this.mContext = context;}/*** 选择图片*/public selectPicture(): Promise<MediaBean> {}/*** 选择文件*/public selectFile(): Promise<MediaBean> {}/*** 拍照*/public async takePhoto(context: common.UIAbilityContext): Promise<MediaBean> {}/*** 封装附件实体类*  * @param uri 文件路径*/private async buildMediaBean(uri: string): Promise<MediaBean> {}/*** 通过Uri查找所选文件信息,插入到MediaBean中* @param mediaBean* @param uri*/private async appendFileInfoToMediaBean(mediaBean: MediaBean, uri: string) {}
}

MediaHelper 类定义了5个方法,

  • selectPicture 提供选择图片功能
  • selectFile 提供选择文件功能
  • takePhoto 提供拍照功能
  • buildMediaBean 内部方法,提供MediaBean对象封装
  • appendFileInfoToMediaBean 内部方法,提供追加查询所选文件的文件信息的功能

通过系统组件选择图片、文件或者拍照之后,系统只是简单的返回一个文件的Uri,如果我们需要展示文件的名称、文件大小、文件类型,需要通过appendFileInfoToMediaBean 方法另外去获取。

下面我们针对这几个方法,增加具体的实现代码:

  1. selectPicture
/*** 选择图片*/public selectPicture(): Promise<MediaBean> {try {let photoSelectOptions = new picker.PhotoSelectOptions();photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;photoSelectOptions.maxSelectNumber = 1;let photoPicker = new picker.PhotoViewPicker();return photoPicker.select(photoSelectOptions).then((photoSelectResult) => {Log.info(this.TAG, 'PhotoViewPicker.select successfully, PhotoSelectResult uri: ' + JSON.stringify(photoSelectResult));if (photoSelectResult && photoSelectResult.photoUris && photoSelectResult.photoUris.length > 0) {let filePath = photoSelectResult.photoUris[0];Log.info(this.TAG, 'PhotoViewPicker.select successfully, PhotoSelectResult uri: ' + filePath);return filePath;}}).catch((err) => {Log.error(this.TAG, 'PhotoViewPicker.select failed with err: ' + err);return err;}).then(async (filePath) => {const mediaBean = await this.buildMediaBean(filePath);return mediaBean;});} catch (err) {Log.error(this.TAG, 'PhotoViewPicker failed with err: ' + err);return Promise.reject(err);}}

选择图片的功能,我们通过系统组件 picker.PhotoViewPicker 来进行图片选择,通过配置PhotoSelectOptions,指定选择的MIMEType类型(这里PhotoViewMIMETypes.IMAGE_TYPE 图片类型) 、选择的图片最大数量 maxSelectNumber ,这里我们实现单选功能,数值设置为1即可。
使用photoPicker.select 拉起系统组件进行选择,然后在回调中获取图片的uri。

  1. selectFile
/*** 选择文件*/public selectFile(): Promise<MediaBean> {try {let documentSelectOptions = new picker.DocumentSelectOptions();let documentPicker = new picker.DocumentViewPicker();return documentPicker.select(documentSelectOptions).then((documentSelectResult) => {Log.info(this.TAG, 'DocumentViewPicker.select successfully, DocumentSelectResult uri: ' + JSON.stringify(documentSelectResult));if (documentSelectResult && documentSelectResult.length > 0) {let filePath = documentSelectResult[0];Log.info(this.TAG, 'DocumentViewPicker.select successfully, DocumentSelectResult uri: ' + filePath);return filePath;}}).catch((err) => {Log.error(this.TAG, 'PhotoViewPicker.select failed with err: ' + err);return err;}).then(async (filePath) => {const mediaBean = await this.buildMediaBean(filePath);return mediaBean;});} catch (err) {Log.error(this.TAG, 'PhotoViewPicker failed with err: ' + err);return Promise.reject(err);}}

选择文件的功能,我们通过系统组件 picker.DocumentViewPicker来进行文件选择,代码基本是跟图片选择是一样的,区别在于DocumentSelectOptions,目前api9并没有配置项提供,具体关注后续的api版本情况。

  1. takePhoto
/*** 拍照*/public async takePhoto(context: common.UIAbilityContext): Promise<MediaBean> {let want = {'uri': '','action': wantConstant.Action.ACTION_IMAGE_CAPTURE,'parameters': {},};return context.startAbilityForResult(want).then((result) => {Log.info(this.TAG, `startAbility call back , ${JSON.stringify(result)}`);if (result.resultCode === 0 && result.want && StringUtils.isNotNullOrEmpty(result.want.uri)) {//拍照成功Log.info(this.TAG, 'takePhoto successfully, takePhotoResult uri: ' + result.want.uri);return result.want.uri;}}).catch((error) => {Log.info(this.TAG, `startAbility error , ${JSON.stringify(error)}`);return error;}).then(async (uri: string) => {const mediaBean = await this.buildMediaBean(uri);return mediaBean;});}

拍照的功能,我们也是拉起相机来进行拍照的,我们使用 startAbilityForResult 方法 + 配置拉起action (wantConstant.Action.ACTION_IMAGE_CAPTURE)的方式拉起系统相机,拍照结束后,在then中接收返回的数据,我们通过返回码result.resultCode 来判断是否进行了拍照,如果状态值===0,说明进行了拍照,我们再使用result.want.uri获取拍照后的照片uri。

  1. buildMediaBean
  /*** 封装多媒体实体类** @param uri 文件路径*/private async buildMediaBean(uri: string): Promise<MediaBean> {if (StringUtils.isNullOrEmpty(uri)) {return null;}const mediaBean: MediaBean = new MediaBean();mediaBean.localUrl = uri;await this.appendFileInfoToMediaBean(mediaBean, uri);return mediaBean;}

这个方法的作用主要是封装一个多媒体实体类,并触发appendFileInfoToMediaBean 获取Uri对应文件的一些文件信息。代码很简单,相信大家一目了然。

  1. appendFileInfoToMediaBean
/*** 通过Uri查找所选文件信息,插入到MediaBean中* @param mediaBean* @param uri*/private async appendFileInfoToMediaBean(mediaBean: MediaBean, uri: string) {if (StringUtils.isNullOrEmpty(uri)) {return;}let fileList: Array<mediaLibrary.FileAsset> = [];const parts: string[] = uri.split('/');const id: string = parts.length > 0 ? parts[parts.length - 1] : '-1';try {let media = mediaLibrary.getMediaLibrary(this.mContext);let mediaFetchOptions: mediaLibrary.MediaFetchOptions = {selections: mediaLibrary.FileKey.ID + '= ?',selectionArgs: [id],uri: uri};let fetchFileResult = await media.getFileAssets(mediaFetchOptions);Log.info(this.TAG, `fileList getFileAssetsFromType fetchFileResult.count = ${fetchFileResult.getCount()}`);fileList = await fetchFileResult.getAllObject();fetchFileResult.close();await media.release();} catch (e) {Log.error(this.TAG, "query: file data  exception ");}if (fileList && fileList.length > 0) {let fileInfoObj = fileList[0];Log.info(this.TAG, `file id = ${JSON.stringify(fileInfoObj.id)} , uri = ${JSON.stringify(fileInfoObj.uri)}`);Log.info(this.TAG, `file fileList displayName = ${fileInfoObj.displayName} ,size = ${fileInfoObj.size} ,mimeType = ${fileInfoObj.mimeType}`);mediaBean.fileName = fileInfoObj.displayName;mediaBean.fileSize = fileInfoObj.size;mediaBean.fileType = fileInfoObj.mimeType;}}

这个方法的作用主要是通过uri查询文件的详细信息,包括文件名称、文件大小、文件类型。

  • 通过Uri获取文件ID。
  • 使用mediaLibrary.getMediaLibrary获取media对象。
  • 配置MediaFetchOptions,主要是ID,通过文件ID来查找文件对象。
  • 使用media.getFileAssets查询文件对象结果,这里可以是批量操作,得到一个FetchFileResult对象。
  • 遍历FileAsset数组,得到文件信息。

这里列下FileAsset的一些字段:

名称类型可读可写说明
idnumber文件资源编号
uristring文件资源uri(如:datashare:///media/image/2)
mimeTypestring文件扩展属性
mediaType8+MediaType媒体类型
displayNamestring显示文件名,包含后缀名
titlestring文件标题
relativePath8+string相对公共目录路径
parent8+number父目录id
sizenumber文件大小(单位:字节)
dateAddednumber添加日期(添加文件时间到1970年1月1日的秒数值)
dateModifiednumber修改日期(修改文件时间到1970年1月1日的秒数值,修改文件名不会改变此值,当文件内容发生修改时才会更新)
dateTakennumber拍摄日期(文件拍照时间到1970年1月1日的秒数值)
artist8+string作者
audioAlbum8+string专辑
widthnumber图片宽度(单位:像素)
heightnumber图片高度(单位:像素)
orientationnumber图片显示方向(顺时针旋转角度,如0,90,180 单位:度)
duration8+number持续时间(单位:毫秒)
albumIdnumber文件所归属的相册编号
albumUri8+string文件所归属相册uri
albumNamestring文件所归属相册名称

这里贴下MediaHelper.ts的完整代码

import common from '@ohos.app.ability.common';
import picker from '@ohos.file.picker';
import mediaLibrary from '@ohos.multimedia.mediaLibrary';
import wantConstant from '@ohos.ability.wantConstant';
import { MediaBean } from '../bean/MediaBean';
import { StringUtils } from '../utils/StringUtils';
import { Log } from '../utils/Log';/*** 多媒体辅助类*/
export class MediaHelper {private readonly TAG: string = 'MediaHelper';private mContext: common.Context;constructor(context: common.Context) {this.mContext = context;}/*** 选择图片*/public selectPicture(): Promise<MediaBean> {try {let photoSelectOptions = new picker.PhotoSelectOptions();photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;photoSelectOptions.maxSelectNumber = 1;let photoPicker = new picker.PhotoViewPicker();return photoPicker.select(photoSelectOptions).then((photoSelectResult) => {Log.info(this.TAG, 'PhotoViewPicker.select successfully, PhotoSelectResult uri: ' + JSON.stringify(photoSelectResult));if (photoSelectResult && photoSelectResult.photoUris && photoSelectResult.photoUris.length > 0) {let filePath = photoSelectResult.photoUris[0];Log.info(this.TAG, 'PhotoViewPicker.select successfully, PhotoSelectResult uri: ' + filePath);return filePath;}}).catch((err) => {Log.error(this.TAG, 'PhotoViewPicker.select failed with err: ' + err);return err;}).then(async (filePath) => {const mediaBean = await this.buildMediaBean(filePath);return mediaBean;});} catch (err) {Log.error(this.TAG, 'PhotoViewPicker failed with err: ' + err);return Promise.reject(err);}}/*** 选择文件*/public selectFile(): Promise<MediaBean> {try {let documentSelectOptions = new picker.DocumentSelectOptions();let documentPicker = new picker.DocumentViewPicker();return documentPicker.select(documentSelectOptions).then((documentSelectResult) => {Log.info(this.TAG, 'DocumentViewPicker.select successfully, DocumentSelectResult uri: ' + JSON.stringify(documentSelectResult));if (documentSelectResult && documentSelectResult.length > 0) {let filePath = documentSelectResult[0];Log.info(this.TAG, 'DocumentViewPicker.select successfully, DocumentSelectResult uri: ' + filePath);return filePath;}}).catch((err) => {Log.error(this.TAG, 'PhotoViewPicker.select failed with err: ' + err);return err;}).then(async (filePath) => {const mediaBean = await this.buildMediaBean(filePath);return mediaBean;});} catch (err) {Log.error(this.TAG, 'PhotoViewPicker failed with err: ' + err);return Promise.reject(err);}}/*** 拍照*/public async takePhoto(context: common.UIAbilityContext): Promise<MediaBean> {let want = {'uri': '','action': wantConstant.Action.ACTION_IMAGE_CAPTURE,'parameters': {},};return context.startAbilityForResult(want).then((result) => {Log.info(this.TAG, `startAbility call back , ${JSON.stringify(result)}`);if (result.resultCode === 0 && result.want && StringUtils.isNotNullOrEmpty(result.want.uri)) {//拍照成功Log.info(this.TAG, 'takePhoto successfully, takePhotoResult uri: ' + result.want.uri);return result.want.uri;}}).catch((error) => {Log.info(this.TAG, `startAbility error , ${JSON.stringify(error)}`);return error;}).then(async (uri: string) => {const mediaBean = await this.buildMediaBean(uri);return mediaBean;});}/*** 封装多媒体实体类** @param uri 文件路径*/private async buildMediaBean(uri: string): Promise<MediaBean> {if (StringUtils.isNullOrEmpty(uri)) {return null;}const mediaBean: MediaBean = new MediaBean();mediaBean.localUrl = uri;await this.appendFileInfoToMediaBean(mediaBean, uri);return mediaBean;}/*** 通过Uri查找所选文件信息,插入到MediaBean中* @param mediaBean* @param uri*/private async appendFileInfoToMediaBean(mediaBean: MediaBean, uri: string) {if (StringUtils.isNullOrEmpty(uri)) {return;}let fileList: Array<mediaLibrary.FileAsset> = [];const parts: string[] = uri.split('/');const id: string = parts.length > 0 ? parts[parts.length - 1] : '-1';try {let media = mediaLibrary.getMediaLibrary(this.mContext);let mediaFetchOptions: mediaLibrary.MediaFetchOptions = {selections: mediaLibrary.FileKey.ID + '= ?',selectionArgs: [id],uri: uri};let fetchFileResult = await media.getFileAssets(mediaFetchOptions);Log.info(this.TAG, `fileList getFileAssetsFromType fetchFileResult.count = ${fetchFileResult.getCount()}`);fileList = await fetchFileResult.getAllObject();fetchFileResult.close();await media.release();} catch (e) {Log.error(this.TAG, "query: file data  exception ");}if (fileList && fileList.length > 0) {let fileInfoObj = fileList[0];Log.info(this.TAG, `file id = ${JSON.stringify(fileInfoObj.id)} , uri = ${JSON.stringify(fileInfoObj.uri)}`);Log.info(this.TAG, `file fileList displayName = ${fileInfoObj.displayName} ,size = ${fileInfoObj.size} ,mimeType = ${fileInfoObj.mimeType}`);mediaBean.fileName = fileInfoObj.displayName;mediaBean.fileSize = fileInfoObj.size;mediaBean.fileType = fileInfoObj.mimeType;}}
}

API标记弃用问题

上面的代码,在api9实测是可以正常使用的,但是有一些API被标记为过期,有一些在官方文档注明即将停用,但是我没有找到可以平替的API,如果有读者知道的,麻烦评论区告诉我一声,谢谢。

  1. ohos.app.ability.wantConstant
    官方提示让我们切换到 ohos.app.ability.wantConstant这个类下,可是我们用到wantConstant.Action,这个Action在 ohos.app.ability.wantConstant中没有定义,我在SDK中也没有找到Action在哪一个类中定义;
  2. mediaLibrary.getMediaLibrary.getFileAssets
    我们需要使用getMediaLibrary获取多媒体对象,调用getFileAssets查询文件的多媒体信息,官方提示让我们使用ohos.file.picker,可笑的是picker中没有getFileAssets 相关的方法,那我们通过picker只能拿到一个文件的Uri,文件名称、文件大小这些常规的文件相关的数据都拿不到,那功能都无法开发,这也是我之前的一个疑问。

动态申请多媒体访问权限

我们读取文件的多媒体信息需要申请一个多媒体的读取权限 ohos.permission.READ_MEDIA,这个权限需要在
module.json5中添加配置requestPermissions,在该节点下配置READ_MEDIA权限,具体如下图:
在这里插入图片描述
由于这个READ_MEDIA权限需要进行动态权限申请,因为还需要我们进行动态权限申请代码逻辑开发,这里由于篇幅原因,我就不过多赘述,后续如果对这块动态权限申请有不明白的地方,我再重新写一篇文章介绍,讲下动态申请权限,跳转系统权限设置页配置权限这些功能具体如何实现。
这次的Demo,我们直接安装后,在系统设置中找到应用,把对应的权限开启即可(绕过权限动态申请)。

实现选择图片显示功能

下面我们编写UI页面,使用我们上面的MediaHelper工具类选择图片、拍照,并将图片显示出来。
在这里插入图片描述

我们在Index.ets文件中放三个按钮,以及显示文件名称、大小、文件类型以及文件路径、显示图片的控件。
完整的代码如下:

import common from '@ohos.app.ability.common';
import { MediaBean } from '../bean/MediaBean';
import { MediaHelper } from '../helper/MediaHelper';@Entry
@Component
struct Index {@State mediaBean: MediaBean = new MediaBean();private mediaHelper: MediaHelper = new MediaHelper(getContext());build() {Row() {Column() {Text('选择图片').textAlign(TextAlign.Center).width(200).fontSize(16).padding(10).margin(20).border({ width: 0.5, color: '#ff38f84b', radius: 15 }).onClick(() => {this.handleClick(MediaOption.Picture)})Text('选择文件').textAlign(TextAlign.Center).width(200).fontSize(16).padding(10).margin(20).border({ width: 0.5, color: '#ff38f84b', radius: 15 }).onClick(() => {this.handleClick(MediaOption.File)})Text('拍照').textAlign(TextAlign.Center).width(200).fontSize(16).padding(10).margin(20).border({ width: 0.5, color: '#ff38f84b', radius: 15 }).onClick(() => {this.handleClick(MediaOption.TakePhoto)})Divider().width('100%').height(0.5).color('#ff99f6a2').margin({ top: 20 }).padding({ left: 20, right: 20 })Text(`文件名称: ${this.mediaBean.fileName ? this.mediaBean.fileName : ''}`).textAlign(TextAlign.Center).width('100%').fontSize(16).margin(10)Text(`文件大小: ${this.mediaBean.fileSize ? this.mediaBean.fileSize : ''}`).textAlign(TextAlign.Center).width('100%').fontSize(16).margin(10)Text(`文件类型: ${this.mediaBean.fileType ? this.mediaBean.fileType : ''}`).textAlign(TextAlign.Center).width('100%').fontSize(16).margin(10)Text(`文件Uri: ${this.mediaBean.localUrl ? this.mediaBean.localUrl : ''}`).textAlign(TextAlign.Center).width('100%').fontSize(16).margin(10)Image(this.mediaBean.localUrl).width(300).height(300).backgroundColor(Color.Grey)}.width('100%').height('100%')}.height('100%')}async handleClick(option: MediaOption) {let mediaBean: MediaBean;switch (option) {case MediaOption.Picture:mediaBean = await this.mediaHelper.selectPicture();break;case MediaOption.File:mediaBean = await this.mediaHelper.selectFile();break;case MediaOption.TakePhoto:mediaBean = await this.mediaHelper.takePhoto(getContext() as common.UIAbilityContext);break;default:break;}if (mediaBean) {this.mediaBean = mediaBean;}}
}enum MediaOption {Picture = 0,File = 1,TakePhoto = 2
}

打包测试

打包安装到真机上,需要我们给项目配置签名信息。我们点击File -> Project Structure ->Project ,选择 Signing Configs面板,勾选 Support HarmonyOS 跟Automatically generate signature,自动生成调试签名,生成完毕后,运行安装到手机上。

使用拍照功能时,请使用真机运行,如果使用的本地模拟器运行,拍照后返回,uri可能会返回“”。

注意:由于我们没有实现多媒体读取权限动态申请权限,因此需要在手机系统设置-应用中找到该应用,开启多媒体权限,该权限默认是禁止的,开启后再打开应用操作即可。运行的具体的效果如文章开头贴图展示一般。

文本到此完毕,有疑问的请在评论区留言交流,谢谢阅读。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

二手车销售技巧 如何卖好二手车

在后疫情时代&#xff0c;消费出现降级&#xff0c;很多原本计划购买新车的消费者&#xff0c;进而把目光投向了二手车&#xff0c;二手车市场遇到了难得的发展机遇。二手车市场作为汽车产业链的重要组成部分&#xff0c;也迎来了前所未有的发展机遇。然而&#xff0c;与此同时…

Git版本管理配置说明 - Visual Studio

一、 Git服务端配置 在源代码管理服务器新建文件夹,并配置共享访问权限Everyone(读取/写入)。 在本地访问这台服务器共享目录,确保正确打开。 在VS中打开项目,点选Git更改,点击“创建Git仓库”,创建项目初始版本。 弹出如下对话框: 因为我们只是在局域网中开发项…

【Linux】命令行参数

文章目录 前言一、C语言main函数的参数二、环境变量总结 前言 我们在Linux命令行输入命令的时候&#xff0c;一般都会跟上一些参数选项&#xff0c;比如l命令&#xff0c;ls -a -l。以前我总是觉得这是理所当然的&#xff0c;没深究其本质究竟是什么&#xff0c;今天才终于知道…

王者小游戏

游戏里的经验动物 Bear package beast; import sxt.GameFrame; public class Bear extends Beast {public Bear(int x, int y, GameFrame gameFrame) {super(x, y, gameFrame);setImg("C:\\Users\\辛欣\\OneDrive\\桌面\\王者荣耀图片(1)\\王者荣耀图片\\beast\\bear.jp…

输入通道数 和 输出通道数 的理解

输入通道数&#xff08;in_channels&#xff09;输出通道数&#xff08;out_channels&#xff09; 在卷积神经网络中通常需要输入 in_channels 和 out_channels &#xff0c;即输入通道数和输出通道数&#xff0c;它们代表什么意思呢&#xff1f; 输入通道数&#xff08;in_c…

软件设计之组合模式

组合模式&#xff1a;将对象组合成树形结构。 案例&#xff1a;公司管理。一个公司可以分总公司和分公司&#xff0c;无论是总公司还是分公司都有自己的部门&#xff0c;如人力资源管理部门、财务部门。分公司可以建立自己在不同地域的办事处。请使用组合模式打印出某个公司的…

JFrog Artifactory—高性能软件制品管理仓库

产品概述 JFrog Artifactory是一个可扩展的通用二进制存储库管理器&#xff0c;可在整个应用程序开发和交付过程中自动管理工件和依赖项。JFrog Artifactory支持大多数开发语言&#xff0c;是整个DevOps流水线中大多数软件包、容器映像和Helm图表的单一数据源。Artifactory对元…

使用Scanner扫描器和if语句来判断QQ等级的活跃程度

一、主要特点 总体使用try包围起来&#xff0c;用到了Scanner扫描器&#xff0c;还用到了若干if语句。 二、运行代码 import java.util.Scanner; public class QQtest {public static void main(String[] args){try (Scanner scan new Scanner(System.in)) {System.out.pr…

物联网开发(一)新版Onenet 基础配置

onenet新创建的账号&#xff0c;没有了多协议接入&#xff0c;只有新的物联网开放平台 第一讲&#xff0c;先给大家讲一下&#xff1a;新版Onenet 基础配置 创建产品 产品开发-->创建产品 产品的品类选择个&#xff1a;大致符合你项目的即可&#xff0c;没有影响 选择智…

Qt应用开发--国产工业开发板全志T113-i的部署教程

Qt在工业上的使用场景包括工业自动化、嵌入式系统、汽车行业、航空航天、医疗设备、制造业和物联网应用。Qt被用来开发工业设备的用户界面、控制系统、嵌入式应用和其他工业应用&#xff0c;因其跨平台性和丰富的功能而备受青睐。 Qt能够为工业领域带来什么好处&#xff1a; -…

顺丰JAVA开发一面—面试实战经验分析【已通过】

文章目录 面试总结面试开始项目相关基础知识反问环节 顺丰JAVA开发一面面试过程中的问题确实涵盖了很多方面&#xff0c;从项目架构到基础知识再到具体技术细节都有所涉及。 面试官的提问风格也是比较开放的&#xff0c;注重考察面试者的深度理解和解决问题的能力。以下是对每个…

tcpdump抓包命令

tcpdump抓包命令 tcpdump 的抓包保存到文件的命令参数是-w xxx.cap 抓eth1的包 tcpdump -i eth1 -w /tmp/xxx.cap抓 192.168.1.123的包 tcpdump -i eth1 host 192.168.1.123 -w /tmp/xxx.cap抓192.168.1.123的80端口的包 tcpdump -i eth1 host 192.168.1.123 and port 80 -w …

深度学习火车票识别系统 计算机竞赛

文章目录 0 前言1 课题意义课题难点&#xff1a; 2 实现方法2.1 图像预处理2.2 字符分割2.3 字符识别部分实现代码 3 实现效果4 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 图像识别 火车票识别系统 该项目较为新颖&#xff0c;适…

【人工智能Ⅰ】实验7:K-means聚类实验

实验7 K-means聚类实验 一、实验目的 学习K-means算法基本原理&#xff0c;实现Iris数据聚类。 二、实验内容 应用K-means算法对iris数据集进行聚类。 三、实验结果及分析 0&#xff1a;输出数据集的基本信息 参考代码在main函数中首先打印了数据、特征名字、目标值、目标…

【STM32】TIM定时器基本定时功能

第一部分&#xff1a;定时器基本定时的功能&#xff1b; 第二部分&#xff1a;定时器的输出比较功能&#xff1b; 第三部分&#xff1a;定时器输入捕获的功能&#xff1b; 第四部分&#xff1a;定时器的编码接口。 1 TIM简介 TIM&#xff08;Timer&#xff09;定时器&#…

实验报告-实验四(时序系统实验)

软件模拟电路图 说明 SW&#xff1a;开关&#xff0c;共六个Q1~Q3&#xff1a;输出Y0~Y3&#xff1a;输出 74LS194 首先&#xff0c;要给S1和S0高电位&#xff0c;将A~D的数据存入寄存器中&#xff08;如果开始没有存入数据&#xff0c;那么就是0000在里面移位&#xff0c;不…

“新KG”视点 | 知识与大模型融合技术在电信领域应用探索

OpenKG 大模型专辑 导读 知识图谱和大型语言模型都是用来表示和处理知识的手段。大模型补足了理解语言的能力&#xff0c;知识图谱则丰富了表示知识的方式&#xff0c;两者的深度结合必将为人工智能提供更为全面、可靠、可控的知识处理方法。在这一背景下&#xff0c;OpenKG组织…

SI24R03 高度集成低功耗SOC 2.4G 收发一体芯片

今天给大家介绍一款Soc 2.4G 收发一体模块-SI24R03 Si24R03是一款高度集成的低功耗无线SOC芯片&#xff0c;芯片为QFN32 5x5mm封装&#xff0c;集成了资源丰富的MCU内核与2.4G收发器模块&#xff0c;最低功耗可达1.6uA&#xff0c;极少外围器件&#xff0c;大幅降低系统应用成本…

DNS协议(DNS规范、DNS报文、DNS智能选路)

目录 DNS协议基本概念 DNS相关规范 DNS服务器的记录 DNS报文 DNS域名查询的两种方式 DNS工作过程 DNS智能选路 DNS协议基本概念 DNS的背景 我们知道主机通信需要依靠IP地址&#xff0c;但是每次通过输入对方的IP地址和对端通信不够方便&#xff0c;IP地址不好记忆 因此提…

【Spring Boot】如何在IntelliJ IDEA中由同一份spring boot源码运行多个不同端口的实例

我们需要使用一个服务有多个实例的测试场景&#xff0c;那么我们就需要在IntelliJ IDEA中通过不同的端口运行不同的实例&#xff0c;并且运行时的源代码是一样的&#xff0c;那么我们可以在IntelliJ IDEA这样操作&#xff0c;接下来以UserApplication服务为例&#xff1a; 复制…