Android NFC开发详解:NFC读卡实例解析及总结

文章目录

  • 前言
  • 一、什么是NFC?
  • 二、基础知识
  • 1.什么是NDEF?
  • 2.NFC技术的操作模式
  • 3.标签的技术类型
  • 4.实现方式的分类
  • 5.流程
  • 三、获取标签内容
  • 1.检查环境
  • 2.获取NFC标签
  • 2.1 Manifest中注册的方式获取Tag
  • 2.1 前台Activity捕获的方式获取Tag
  • 四、解析标签数据
  • 1. M1卡解析
  • 2. iso15693卡解析
  • 总结

一、什么是NFC?

NFC是目前Android手机一个主流的配置硬件项,全称是Near Field Communication,中为近场通信,也叫做近距离无线通信技术。使用了NFC技术的设备(例如移动电话)可以在彼此靠近的情况下进行数据交换,是由非接触式射频识别(RFID)及互连互通技术整合演变而来。

二、基础知识

开始开发之前必须要知道的知识

1.什么是NDEF?

存储在NFC标签中的数据可以采用多种格式编写,但许多 Android 框架 API 都基于名为 NDEF(NFC 数据交换格式)的 NFC Forum 标准。。

简单说就是一种普遍的数据格式标准

2.NFC技术的操作模式

(1) 读取器/写入器模式:支持 NFC 设备读取和/或写入被动 NFC 标签和贴纸。
(2)点对点模式:支持 NFC 设备与其他 NFC 对等设备交换数据;Android Beam 使用的就是此操作模式。
(3)卡模拟模式:支持 NFC 设备本身充当 NFC 卡。然后,可以通过外部 NFC 读取器(例如 NFC 销售终端)访问模拟 NFC 卡。

本篇案例使用的主要是读写卡,就是正常的读写卡需求,后面如果有机会接触到点对点和卡模拟的需求会在此篇做补充

3.标签的技术类型

通常情况下每种分类的标签(卡片)都支持一种或多重技术,
对应关系如下

技术描述卡种
NfcA提供NFC-A(ISO 14443-3A)的性能和I / O操作的访问。M1卡
NfcB提供NFC-B (ISO 14443-3B)的性能和I / O操作的访问。
NfcF提供 NFC-F (JIS 6319-4)的性能和I / O操作的访问。
NfcV提供 NFC-V (ISO 15693)的性能和I / O操作的访问。15693卡
IsoDep提供 ISO-DEP (ISO 14443-4)的性能和I / O操作的访问。CPU卡
Ndef提供NFC标签已被格式化为NDEF的数据和操作的访问。
NdefFormatable提供可能被格式化为NDEF的 formattable的标签。
MifareClassic如果此Android设备支持MIFARE,提供访问的MIFARE Classic性能和I / O操作。m1卡
MifareUltralight如果此Android设备支持MIFARE,提供访问的MIFARE 超轻性能和I / O操作。

如下图,这是Demo 显示得NFC标签的信息。
其中被我圈起来的部分是这个NFC标签支持的技术,这些后面解析数据的时候会用到,得到这些后就可以使用对应的类来解析标签数据。
 


开发中我们有对应的方法来获取此标签支持的解析方式,后面我会介绍。

4.实现方式的分类

(1)Manifest注册方式:这种方式主要是在Manifest文件对应的activity下,配置过滤器,以响应不同类型NFC Action。使用这种方式,在刷卡时,如果手机中有多个应用都存在该NFC实现方案,系统会弹出能响应NFC事件的应用列表供用户选择,用户需要点击目标应用来响应本次NFC刷卡事件。

(2)前台响应方式,无需Manifest重配置过滤器,直接使用前台activity来捕获NFC事件进行响应。

区别如下:
响应方式不同:Manifest注册的NFC事件由系统分发,需要选择应用去响应事件
       前台响应方式由前台activity来捕获NFC事件进行响应
优先级不同:前台响应方式的优先级更高于Manifest注册的方式
     (如果安装多个Manifest注册的的App 和一个处于前台捕获方式的App,刷卡后 优先级最高的为前台捕获的,如果前台相应方式的App没有打开,那么将弹出列表让用户选择Manifest中注册了的符合条件的App)

第一种更适合APP需要刷卡调用起来,并且设备没有多个响应NFC标签程序的物联网设备(因为普通安卓手机中自带的卡包APP、微信等优先级都比较高,当弹出列表选择响应的App时,操作会边得繁琐)

第二种更适合前台界面中的读卡,且多个应用的时候
根据自己的项目需求选择适合的实现方式。

5.流程

首先设备要支持NFC权限开启的前提下 不论哪种方式,都是先刷卡,等待系统分发响应的Activity 拿到Tag或者 前台Activity捕获到TAG 。然后根据这个标签支持的技术去解析数据。

三、获取标签内容

1.检查环境

首先 Manifest中添加权限

    <uses-permission android:name="android.permission.NFC" />

判断是否支持NFC、且打开功能

 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);if (null == adapter) {Toast.makeText(this, "不支持NFC功能", Toast.LENGTH_SHORT).show();} else if (!adapter.isEnabled()) {Intent intent = new Intent(Settings.ACTION_NFC_SETTINGS);// 根据包名打开对应的设置界面startActivity(intent);}

2.获取NFC标签

2.1 Manifest中注册的方式获取Tag

这里要介绍三种意图过滤器
前面【实现方式的分类】中对这种方式的特征做了介绍,这种由标签调度系统分发的方式需要在Manifest定义固定的意图过滤器。标签调度系统定义了三种 Intent,按优先级从高到低列出如下:

ACTION_NDEF_DISCOVERED:如果扫描到包含 NDEF 负载的标签,并且可识别其类型,则使用此 Intent 启动 Activity。这是优先级最高的 Intent,标签调度系统会尽可能尝试使用此 Intent 启动 Activity,在行不通时才会尝试使用其他 Intent。

ACTION_TECH_DISCOVERED:如果没有登记要处理 ACTION_NDEF_DISCOVERED Intent 的 Activity,则标签调度系统会尝试使用此 Intent 来启动应用。此外,如果扫描到的标签包含无法映射到 MIME 类型或 URI 的 NDEF 数据,或者该标签不包含 NDEF 数据,但它使用了已知的标签技术,那么也会直接启动此 Intent(无需先启动 ACTION_NDEF_DISCOVERED)。

ACTION_TAG_DISCOVERED:如果没有处理 ACTION_NDEF_DISCOVERED 或者 ACTION_TECH_DISCOVERED Intent 的 Activity,则使用此 Intent 启动 Activity。

添加意图过滤器
这是第一种 最简单和优先级最高的一种,已经满足需求了

        <activityandroid:name=".NfcActivity"android:exported="false"><intent-filter><action android:name="android.nfc.action.NDEF_DISCOVERED" /></intent-filter></activity>

当然也可以选择第二种

        <activityandroid:name=".NfcActivity"android:exported="false"><intent-filter><action android:name="android.nfc.action.TECH_DISCOVERED" /></intent-filter><meta-data android:name="android.nfc.action.TECH_DISCOVERED"android:resource="@xml/filter_nfc" /></activity>

filter_nfc
这个文件就是TECH_DISCOVERED需要配置的,其中,tech-list之间是逻辑或关系,tech之间是逻辑与关系,与方案2中的techLists原理以及用途是类似。

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"><tech-list><tech>android.nfc.tech.Ndef</tech><tech>android.nfc.tech.NfcA</tech></tech-list><tech-list><tech>android.nfc.tech.NfcB</tech></tech-list><tech-list><tech>android.nfc.tech.NfcF</tech></tech-list>
</resources>

还剩最后一种

        <activityandroid:name=".NfcActivity"android:exported="false"><intent-filter><action android:name="android.nfc.action.TAG_DISCOVERED"/><category android:name="android.intent.category.DEFAULT"/></intent-filter></activity>

这种一般用不到 感觉意义不大

然后在对应Activity的onCreate方法中就可以拿标签了

class NfcActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_nfc)val adapter = NfcAdapter.getDefaultAdapter(this)if (null == adapter) {Toast.makeText(this, "不支持NFC功能", Toast.LENGTH_SHORT).show()} else if (!adapter.isEnabled) {val intent = Intent(Settings.ACTION_NFC_SETTINGS)// 根据包名打开对应的设置界面startActivity(intent)}val tag = intent.getParcelableExtra<Tag>(NfcAdapter.EXTRA_TAG)}
}

2.1 前台Activity捕获的方式获取Tag

class MainActivity : AppCompatActivity() {var mNfcAdapter: NfcAdapter? = nullvar pIntent: PendingIntent? = nulloverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)initNfc()}private fun initNfc() {mNfcAdapter = M1CardUtils.isNfcAble(this)pIntent = PendingIntent.getActivity(this, 0,  //在Manifest里或者这里设置当前activity启动模式,否则每次响应NFC事件,activity会重复创建Intent(this, javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0)}override fun onResume() {super.onResume()mNfcAdapter?.let {val ndef = IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED)val tag = IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED)val tech = IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED)val filters = arrayOf(ndef, tag, tech)val techList = arrayOf(arrayOf("android.nfc.tech.Ndef","android.nfc.tech.NfcA","android.nfc.tech.NfcB","android.nfc.tech.NfcF","android.nfc.tech.NfcV","android.nfc.tech.NdefFormatable","android.nfc.tech.MifareClassic","android.nfc.tech.MifareUltralight","android.nfc.tech.NfcBarcode"))it.enableForegroundDispatch(this, pIntent, filters, techList)XLog.d("开始捕获NFC数据")}}override fun onPause() {super.onPause()mNfcAdapter?.disableForegroundDispatch(this)}override fun onNewIntent(intent: Intent?) {super.onNewIntent(intent)//这里必须setIntent,set  NFC事件响应后的intent才能拿到数据setIntent(intent)val tag = getIntent().getParcelableExtra<Tag>(NfcAdapter.EXTRA_TAG)//M1CardUtils 我后面会贴出来的if (M1CardUtils.isMifareClassic(tag)) {try {val reader = M1CardUtils.readCard(tag)XLog.d("读卡内容:$reader")val data = reader.split("|")} catch (e: IOException) {e.printStackTrace()}}}
}

四、解析标签数据

不论使用哪种方式,当我们获取到TAG标签后,解析方式都是相同的,需要根据不同的卡类型选择对应的解析方式
 


如图 我们能拿到卡片的信息,如图,括起来的部分分别对应的是:
支持的技术类型
MifareClassic 类型
扇区存储空间
扇区数
扇区中的块数

1. M1卡解析

这里说一下基础知识,不论是NFC还是读卡模块读,解析流程都是先寻卡,然后验证扇区的密码,取扇区的数据,比如已知要读的数据在2扇区,那么寻卡后验证时把要验证的扇区号、扇区的密码,和扇区的验证密码类型A/B传过去验证通过后,就可以读取数据了。


import android.app.Activity
import android.nfc.NfcAdapter
import android.nfc.Tag
import com.hjq.toast.ToastUtils
import kotlin.Throws
import android.nfc.tech.MifareClassic
import com.elvishew.xlog.XLog
import java.io.IOException
import java.lang.StringBuilder
import java.nio.charset.Charsetobject M1CardUtils {/*** 判断是否支持NFC** @return*/fun isNfcAble(mContext: Activity?): NfcAdapter? {val mNfcAdapter = NfcAdapter.getDefaultAdapter(mContext)if (mNfcAdapter == null) {ToastUtils.show("设备不支持NFC!")}if (!mNfcAdapter!!.isEnabled) {ToastUtils.show("请在系统设置中先启用NFC功能!")}return mNfcAdapter}/*** 监测是否支持MifareClassic** @param tag* @return*/fun isMifareClassic(tag: Tag): Boolean {val techList = tag.techListvar haveMifareUltralight = falsefor (tech in techList) {if (tech.contains("MifareClassic")) {haveMifareUltralight = truebreak}}if (!haveMifareUltralight) {ToastUtils.show("不支持MifareClassic")return false}return true}/*** 读取卡片信息** @return*/@Throws(IOException::class)fun readCard(tag: Tag?): String {val mifareClassic = MifareClassic.get(tag)return try {mifareClassic.connect()val metaInfo = StringBuilder()val gbk = Charset.forName("gbk")// 获取TAG中包含的扇区数val sectorCount = mifareClassic.sectorCount//            for (int j = 0; j < sectorCount; j++) {val bCount: Int //当前扇区的块数var bIndex: Int //当前扇区第一块if (m1Auth(mifareClassic, 2)) {bCount = mifareClassic.getBlockCountInSector(2)bIndex = mifareClassic.sectorToBlock(2)var length = 0for (i in 0 until bCount) {val data = mifareClassic.readBlock(bIndex)for (i1 in data.indices) {if (data[i1] == 0.toByte()) {length = i1}}val dataString = String(data, 0, length, gbk).trim { it <= ' ' }metaInfo.append(dataString)bIndex++}} else {XLog.e("密码校验失败")}//            }metaInfo.toString()} catch (e: IOException) {throw IOException(e)} finally {try {mifareClassic.close()} catch (e: IOException) {throw IOException(e)}}}/*** 改写数据** @param block* @param blockbyte*/@Throws(IOException::class)fun writeBlock(tag: Tag?, block: Int, blockbyte: ByteArray?): Boolean {val mifareClassic = MifareClassic.get(tag)try {mifareClassic.connect()if (m1Auth(mifareClassic, block / 4)) {mifareClassic.writeBlock(block, blockbyte)XLog.e("writeBlock", "写入成功")} else {XLog.e("密码是", "没有找到密码")return false}} catch (e: IOException) {throw IOException(e)} finally {try {mifareClassic.close()} catch (e: IOException) {throw IOException(e)}}return true}/*** 密码校验** @param mTag* @param position* @return* @throws IOException*/@Throws(IOException::class)fun m1Auth(mTag: MifareClassic, position: Int): Boolean {if (mTag.authenticateSectorWithKeyA(position, MifareClassic.KEY_DEFAULT)) {return true} else if (mTag.authenticateSectorWithKeyB(position, MifareClassic.KEY_DEFAULT)) {return true}return false}}

2. iso15693卡解析

本案例中没有用到这种,只是需要M1所以不需要这个,这是别的大佬封装的类发出来供参考

import android.nfc.tech.NfcV;import com.haiheng.core.util.ByteUtils;import java.io.IOException;/*** NfcV(ISO 15693)读写操作*   用法*  NfcV mNfcV = NfcV.get(tag);*  mNfcV.connect();* <p>*  NfcVUtils mNfcVutil = new NfcVUtils(mNfcV);*  取得UID*  mNfcVutil.getUID();*  读取block在1位置的内容*  mNfcVutil.readOneBlock(1);*  从位置7开始读2个block的内容*  mNfcVutil.readBlocks(7, 2);*  取得block的个数*  mNfcVutil.getBlockNumber();*  取得1个block的长度*  mNfcVutil.getOneBlockSize();*  往位置1的block写内容*  mNfcVutil.writeBlock(1, new byte[]{0, 0, 0, 0})** @author Kelly* @version 1.0.0* @filename NfcVUtils.java* @time 2018/10/30 10:29* @copyright(C) 2018 song*/
public class NfcVUtils {private NfcV mNfcV;/*** UID数组行式*/private byte[] ID;private String UID;private String DSFID;private String AFI;/*** block的个数*/private int blockNumber;/*** 一个block长度*/private int oneBlockSize;/*** 信息*/private byte[] infoRmation;/***  * 初始化*  * @param mNfcV NfcV对象*  * @throws IOException*  */public NfcVUtils(NfcV mNfcV) throws IOException {this.mNfcV = mNfcV;ID = this.mNfcV.getTag().getId();byte[] uid = new byte[ID.length];int j = 0;for (int i = ID.length - 1; i >= 0; i--) {uid[j] = ID[i];j++;}this.UID = ByteUtils.byteArrToHexString(uid);getInfoRmation();}public String getUID() {return UID;}/***  * 取得标签信息 *  */private byte[] getInfoRmation() throws IOException {byte[] cmd = new byte[10];cmd[0] = (byte) 0x22; // flagcmd[1] = (byte) 0x2B; // commandSystem.arraycopy(ID, 0, cmd, 2, ID.length); // UIDinfoRmation = mNfcV.transceive(cmd);blockNumber = infoRmation[12];oneBlockSize = infoRmation[13];AFI = ByteUtils.byteArrToHexString(new byte[]{infoRmation[11]});DSFID = ByteUtils.byteArrToHexString(new byte[]{infoRmation[10]});return infoRmation;}public String getDSFID() {return DSFID;}public String getAFI() {return AFI;}public int getBlockNumber() {return blockNumber + 1;}public int getOneBlockSize() {return oneBlockSize + 1;}/***  * 读取一个位置在position的block*  * @param position 要读取的block位置*  * @return 返回内容字符串*  * @throws IOException*  */public String readOneBlock(int position) throws IOException {byte cmd[] = new byte[11];cmd[0] = (byte) 0x22;cmd[1] = (byte) 0x20;System.arraycopy(ID, 0, cmd, 2, ID.length); // UIDcmd[10] = (byte) position;byte res[] = mNfcV.transceive(cmd);if (res[0] == 0x00) {byte block[] = new byte[res.length - 1];System.arraycopy(res, 1, block, 0, res.length - 1);return ByteUtils.byteArrToHexString(block);}return null;}/***  * 读取从begin开始end个block*  * begin + count 不能超过blockNumber*  * @param begin block开始位置*  * @param count 读取block数量*  * @return 返回内容字符串*  * @throws IOException*  */public String readBlocks(int begin, int count) throws IOException {if ((begin + count) > blockNumber) {count = blockNumber - begin;}StringBuffer data = new StringBuffer();for (int i = begin; i < count + begin; i++) {data.append(readOneBlock(i));}return data.toString();}/***  * 将数据写入到block,*  * @param position 要写内容的block位置*  * @param data 要写的内容,必须长度为blockOneSize*  * @return false为写入失败,true为写入成功*  * @throws IOException *  */public boolean writeBlock(int position, byte[] data) throws IOException {byte cmd[] = new byte[15];cmd[0] = (byte) 0x22;cmd[1] = (byte) 0x21;System.arraycopy(ID, 0, cmd, 2, ID.length); // UID//blockcmd[10] = (byte) position;//valueSystem.arraycopy(data, 0, cmd, 11, data.length);byte[] rsp = mNfcV.transceive(cmd);if (rsp[0] == 0x00)return true;return false;}
}

总结

以上就是今天要讲的内容,文章中如有错误或者需要改进的地方欢迎补充指正,本文仅介绍了NFC的使用和M1卡的读取解析场景,关于NFC的历史、卡片类型、Intent filter类型详细描述,其他使用场景等可以参考更多文档,这里贴出来几个我看到的对我很有帮助的文章,也欢迎大家多做参考,

NFC 各种卡类型、区别、历史介绍
https://zhuanlan.zhihu.com/p/344426747
各种官方资料中文说明
https://blog.csdn.net/u013164293/article/details/124474247?spm=1001.2014.3001.5506

 

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

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

相关文章

配置Hive使用Spark执行引擎

配置Hive使用Spark执行引擎 Hive引擎概述兼容问题安装SparkSpark配置Hive配置HDFS上传Spark的jar包执行测试速度对比 Hive引擎 概述 在Hive中&#xff0c;可以通过配置来指定使用不同的执行引擎。Hive执行引擎包括&#xff1a;默认MR、tez、spark MapReduce引擎&#xff1a; 早…

英码边缘计算盒子IVP03X——32T超强算力,搭载BM1684X算能TPU处理器

产品8大优势&#xff1a; 高效节能&#xff1a;相较异构产品&#xff0c;IVP03X数据调配效率更高&#xff0c;资源利用率更高&#xff0c;平均功耗更低&#xff1b;升级换代&#xff1a;相较算能BM1684平台&#xff0c;IVP03X算力、编码&#xff0c;模型转换性能均翻倍提升&am…

Easysearch Chart 0.2.0都有哪些变化

Easysearch Chart 包更新了&#xff0c;让我们来看看都有哪些变化&#xff1a; Docker 镜像升级 Service 名称调整&#xff0c;支持 NodePort 模式部署 现在让我们用 NodePort 模式部署一下&#xff1a; # helm search repo infinilabs NAME CHART VERSION …

VS2022+qt5.15.2+cmake3.23.2配置VTK9.1.0版本

VS2022qt5.15.2cmake3.23.2VTK9.1.0 尝试了好多次&#xff0c;终于成了~ 软件安装 先把需要的软件都安装好&#xff01; VS2022安装教程: https://blog.csdn.net/qq_44005305/article/details/132295064 qt5.15.2安装教程&#xff1a;https://blog.csdn.net/Qi_1337/article…

PLC之间无线通信-不用编程实现多品牌PLC无线通讯的解决方案

本文是PLC设备之间基于IGT-DSER系列智能网关实现WIFI无线通讯的案例。采用西门子S7-1500系列的PLC作为主站&#xff0c;与其它品牌的PLC之间进行网络通讯。案例包括智能网关AP方式、现场WIFI信号两种方式。有线以太网方式实现PLC之间通讯的案例 一、智能网关AP方式 将网络中的其…

SpringBatch适配不同数据库的两种方法

一、配置JobRepository Configuration EnableBatchProcessing public class TaskArrangeConfig extends DefaultBatchConfigurer {Autowiredprivate DataSource dataSource;Autowiredprivate JobLauncher jobLauncher;Autowiredprivate JobExplorer jobExplorer;Autowiredpriv…

李沐深度学习记录4:12.权重衰减/L2正则化

权重衰减从零开始实现 #高维线性回归 %matplotlib inline import torch from torch import nn from d2l import torch as d2l#整个流程是&#xff0c;1.生成标准数据集&#xff0c;包括训练数据和测试数据 # 2.定义线性模型训练 # 模型初始化&#xff08;函…

springboot 捕获特点异常信息并处理

前端获取效果图 springboot 捕获特点异常信息并处理 import com.one.utils.JSONResult; //JSONResult定义处理结果对象 import org.springframework.web.bind.annotation.ExceptionHandler

35.树与二叉树练习(1)(王道第5章综合练习)

【所用的树&#xff0c;队列&#xff0c;栈的基本操作详见上一节代码】 试题1&#xff08;王道5.3.3节第3题&#xff09;&#xff1a; 编写后序遍历二叉树的非递归算法。 参考&#xff1a;34.二叉链树的C语言实现_北京地铁1号线的博客-CSDN博客https://blog.csdn.net/qq_547…

3D 生成重建005-NeRF席卷3D的表达形式

3D生成重建005-NeRF席卷3D的表达形式 文章目录 0 论文工作1 论文方法1.1 体渲染1.2 离散积分1.3位置编码1.4分层采样1.5 影响 2 效果 0 论文工作 NeRF(神经辐射场技术)最早2020年提出用于新视图合成任务&#xff0c;并在这个领域取得了优秀的效果。如下图所示&#xff0c;受到…

Springcloud笔记(2)-Eureka服务注册

Eureka服务注册 服务注册&#xff0c;发现。 在Spring Cloud框架中&#xff0c;Eureka的核心作用是服务的注册和发现&#xff0c;并实现服务治理。 Eureka包含两个组件&#xff1a;Eureka Server和Eureka Client。 Eureka Server提供服务注册服务&#xff0c;各个节点启动后…

mysql面试题31:一条SQL语句在MySQL中如何执行的

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:一条SQL语句在MySQL中如何执行的 以下是一条SQL语句在MySQL中的详细执行步骤: 语法分析:MySQL首先对SQL语句进行语法分析,检查SQL语句是否符合…

ARM-流水灯

.text .global _start _start: 1、设置GPIOE寄存器的时钟使能 RCC_MP_AHB$ENSETR[4]->1 0x50000a28LDR R0,0X50000A28 LDR R1,[R0] 从R0起始地址的4字节数据取出放在R1 ORR R1,R1,#(0X3<<4) 第4位设置为1 STR R1,[R0] 写回2、设置PE10、PE8、PF10管脚为输出模式 …

elasticSearch7.9数据占用磁盘存储空间情况

最近&#xff0c;在VMware Workstation虚拟机上安装了es7.9&#xff0c;单节点的es&#xff0c;不是集群&#xff0c;然后建了一个索引&#xff08;包含3个分片和一个副本&#xff09;&#xff0c;插入了500万条数据&#xff0c;占据磁盘空间17G。如下图&#xff1a; 索引的字…

在两个有序数组中找整体第k小的数

一、题目 给定两个已经排序的数组&#xff08;假设按照升序排列&#xff09;&#xff0c;然后找出第K小的数。比如数组A {1&#xff0c; 8&#xff0c; 10&#xff0c; 20}&#xff0c; B {5&#xff0c; 9&#xff0c; 22&#xff0c; 110}&#xff0c; 第 3 小的数是 8.。…

基于Springboot实现点餐平台网站管理系统项目【项目源码+论文说明】分享

基于Springboot实现点餐平台网站管理系统演示 摘要 随着现在网络的快速发展&#xff0c;网上管理系统也逐渐快速发展起来&#xff0c;网上管理模式很快融入到了许多商家的之中&#xff0c;随之就产生了“点餐平台网站”&#xff0c;这样就让点餐平台网站更加方便简单。 对于本…

解决远程git服务器路径改变导致本地无法push的问题

解决远程git服务器路径改变导致本地无法push的问题 &#xff08;1&#xff09;第一步&#xff1a;查看git配置 git config -l&#xff08;2&#xff09;第二步&#xff1a;删除远程git地址 git remote remove origin&#xff08;3&#xff09;第三步&#xff1a;再次查看git配…

ELK 处理 SpringCloud 日志

在排查线上异常的过程中&#xff0c;查询日志总是必不可缺的一部分。现今大多采用的微服务架构&#xff0c;日志被分散在不同的机器上&#xff0c;使得日志的查询变得异常困难。工欲善其事&#xff0c;必先利其器。如果此时有一个统一的实时日志分析平台&#xff0c;那可谓是雪…

Mall脚手架总结(三) —— MongoDB存储浏览数据

前言 通过Elasticsearch整合章节的学习&#xff0c;我们了解SpringData框架以及相应的衍生查询的方式操作数据读写的语法。MongoDB的相关操作也同样是借助Spring Data框架&#xff0c;因此这篇文章的内容比较简单&#xff0c;重点还是弄清楚MongoDB的使用场景以及如何通过Sprin…

【计算机网络】UDP协议编写群聊天室----附代码

UDP构建服务器 x 预备知识 认识UDP协议 此处我们也是对UDP(User Datagram Protocol 用户数据报协议)有一个直观的认识; 后面再详细讨论. 传输层协议无连接不可靠传输面向数据报 网络字节序 我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的…