当前位置: 首页 > article >正文

随笔20250530 C# 整合 IC卡读写技术解析与实现

以下是一个完整、最简化的 FeliCa 读取整合示例(无需 SDK,基于 PCSC NuGet 包),你可以直接运行这个控制台程序,验证能否识别 RC-S300 并读取卡片 UID:


🧪 示例说明

  • 📦 使用 NuGet 包 PCSC

  • 🎯 功能:初始化读卡器,读取插卡的 UID(部分 FeliCa 卡支持)

  • ✅ 仅依赖 Windows 驱动(无需 SDK)


🛠 使用方式

1. 创建控制台项目

dotnet new console -n FelicaReaderExample
cd FelicaReaderExample

2. 安装依赖包

dotnet add package PCSC

 

直接选第一个宝贝!!! 

3. 替换 Program.cs

将下载的 FelicaReaderExample.cs 文件内容,覆盖 Program.cs

或直接复制粘贴内容。

4. 运行程序

插入 FeliCa 卡到 RC-S300,然后运行:

dotnet run

✅ 成功输出示例

找到读卡器:Sony RC-S300
读取成功,卡片 UID: 01-23-45-67-89-AB-CD

FelicaReaderService.cs 

using System;
using System.Linq;
using System.Threading.Tasks;
using PCSC;
using PCSC.Utils;namespace StarMauiPrinter.Services
{/// <summary>/// 提供对 FeliCa 卡(如 ICOCA)的读取功能,仅获取 UID(IDm)/// </summary>public class FelicaReaderService{/// <summary>/// 读取 FeliCa 卡的唯一识别码(IDm / UID)/// </summary>/// <returns>UID 字符串 或 错误信息</returns>public async Task<string?> ReadCardUidAsync(){try{// 1. 建立与 PC/SC 子系统的连接上下文using var context = ContextFactory.Instance.Establish(SCardScope.System);// 2. 获取所有已连接的智能卡读卡器列表var readerNames = context.GetReaders();if (readerNames == null || readerNames.Length == 0)return "未检测到任何读卡器。";var readerName = readerNames[0];// 3. 使用第一个读卡器进行连接using var reader = new SCardReader(context);var result = reader.Connect(readerName, SCardShareMode.Shared, SCardProtocol.Any);if (result != SCardError.Success)return $"连接失败: {SCardHelper.StringifyError(result)}";// 4. 构造 APDU 指令读取 UID(IDm)// 标准 PC/SC 指令: FF CA 00 00 00var command = new byte[] { 0xFF, 0xCA, 0x00, 0x00, 0x00 };var receivePci = new SCardPCI();var sendPci = SCardPCI.GetPci(reader.ActiveProtocol);var receiveBuffer = new byte[256];// 5. 发送指令并接收响应var transmitResult = reader.Transmit(sendPci,        // 协议控制结构command,        // 发送的指令receivePci,     // 接收的控制结构ref receiveBuffer // 输出缓冲区);if (transmitResult != SCardError.Success)return $"发送失败: {SCardHelper.StringifyError(transmitResult)}";// 6. 解析返回的 UID(通常为 8 字节的 IDm)var uid = receiveBuffer.TakeWhile(b => b != 0x00).ToArray();if (uid.Length == 0)return "未读取到卡片 UID";return $"UID: {BitConverter.ToString(uid)}";}catch (Exception ex){return $"异常: {ex.Message}";}}}
}

 FelicaReaderTest.razor

@page "/felicareadertest"
@inject StarMauiPrinter.Services.FelicaReaderService FelicaReaderService<h3>ICOCA UID を取得する</h3><button class="btn btn-primary" @onclick="ReadUid">取得</button>
<p>@uid</p>@code {private string? uid;private async Task ReadUid(){try{uid = await FelicaReaderService.ReadCardUidAsync();}catch (Exception ex){uid = $"読み取りに失敗しました: {ex.Message}";}}
}
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;
using PCSC;
using PCSC.Utils;namespace StarMauiPrinter.Services
{/// <summary>/// Felica读卡器服务类,用于读取ICOCA等Felica格式的IC卡信息/// </summary>public class FelicaReaderService{#region 常量定义/// <summary>/// 获取UID的APDU命令/// </summary>private static readonly byte[] GET_UID_COMMAND = { 0xFF, 0xCA, 0x00, 0x00, 0x00 };/// <summary>/// 接收缓冲区大小/// </summary>private const int RECEIVE_BUFFER_SIZE = 256;/// <summary>/// 最大重试次数/// </summary>private const int MAX_RETRY_COUNT = 3;/// <summary>/// 重试延迟基数(毫秒)/// </summary>private const int RETRY_DELAY_BASE = 500;#endregion#region 公共方法/// <summary>/// 异步读取卡片UID(带重试机制)/// </summary>/// <returns>返回UID字符串,如果失败则返回错误信息</returns>public async Task<string> ReadCardUidAsync(){return await ExecuteWithRetryAsync(async () =>{// 方案1:直接创建SCardContext实例using var context = new SCardContext();context.Establish(SCardScope.System);// 获取可用读卡器var readerName = GetFirstAvailableReader(context);// 连接读卡器并读取UIDusing var reader = new SCardReader(context);ConnectToCard(reader, readerName);var uid = ReadCardUid(reader);return FormatUid(uid);});}/// <summary>/// 简化版:异步读取ICOCA卡的详细信息/// </summary>/// <returns>返回包含UID、余额和基本信息的字符串</returns>public async Task<string> ReadIcocaDetailsAsync(){return await ExecuteWithRetryAsync(async () =>{using var context = new SCardContext();context.Establish(SCardScope.System);var readerName = GetFirstAvailableReader(context);using var reader = new SCardReader(context);ConnectToCard(reader, readerName);// 读取基本UID信息var uid = ReadCardUid(reader);var uidString = FormatUid(uid);// 尝试读取余额var balance = TryReadBalance(reader);// 尝试读取最近一次交易var lastTransaction = TryReadLastTransaction(reader);return $"ICOCA卡信息:\n" +$"UID: {uidString}\n" +$"余额: {balance}\n" +$"最近交易: {lastTransaction}";});}/// <summary>/// 尝试读取余额(修复版)/// </summary>private string TryReadBalance(SCardReader reader){try{// ICOCA余额读取命令var command = new byte[] { 0xFF, 0xCA, 0x00, 0x01, 0x04, 0x8B, 0x00, 0x83, 0x00 };var response = new byte[64];// 修复:正确使用ref参数var result = reader.Transmit(command, ref response);// 检查命令是否成功执行if (result == SCardError.Success){// 检查响应长度var actualLength = response.Length;if (actualLength >= 4){// 正确解析余额数据var balance = (response[1] << 8) | response[0];  // Little-endianif (balance > 0 && balance < 50000){return $"¥{balance}";}// 尝试其他可能的位置for (int i = 0; i < actualLength - 1; i++){var testBalance = (response[i + 1] << 8) | response[i];if (testBalance > 0 && testBalance < 50000){return $"¥{testBalance}";}}}}else{return $"命令失败: {result}";}}catch (Exception ex){return $"读取失败: {ex.Message}";}return "无法读取";}/// <summary>/// 尝试读取最近一次交易(修复版)/// </summary>private string TryReadLastTransaction(SCardReader reader){try{// 交易记录读取命令var command = new byte[] { 0xFF, 0xCA, 0x00, 0x02, 0x04, 0x8C, 0x00, 0x80, 0x00 };var response = new byte[64];// 修复:正确使用ref参数var result = reader.Transmit(command, ref response);if (result == SCardError.Success && response.Length >= 8){var amount = (response[5] << 8) | response[4];var type = response[0] == 0x05 ? "乘车" : "其他";if (amount > 0 && amount < 10000) // 合理的交易金额范围{return $"{type} ¥{amount}";}}}catch (Exception){// 忽略错误}return "无记录";}/// <summary>/// 检查读卡器状态/// </summary>/// <returns>返回读卡器状态信息</returns>public async Task<string> CheckReaderStatusAsync(){return await Task.Run(() =>{try{// 修复:直接创建SCardContext实例using var context = new SCardContext();context.Establish(SCardScope.System);var readerNames = context.GetReaders();if (readerNames.Length == 0)return "状态: 未检测到任何读卡器";var statusInfo = new List<string>();foreach (var readerName in readerNames){try{// 检查读卡器中是否有卡var cardStatus = CheckCardPresence(context, readerName);statusInfo.Add($"读卡器: {readerName} - 状态: {cardStatus}");}catch (Exception ex){statusInfo.Add($"读卡器: {readerName} - 状态: 检查失败 ({ex.Message})");}}return string.Join("\n", statusInfo);}catch (Exception ex){return $"检查状态时发生异常: {ex.Message}";}});}/// <summary>/// 测试读卡器连接/// </summary>/// <returns>连接测试结果</returns>public async Task<string> TestReaderConnectionAsync(){return await Task.Run(() =>{try{using var context = ContextFactory.Instance.Establish(SCardScope.System);var readerNames = context.GetReaders();if (readerNames.Length == 0)return "测试失败: 未检测到任何读卡器";var readerName = readerNames[0];using var reader = new SCardReader(context);var result = reader.Connect(readerName, SCardShareMode.Shared, SCardProtocol.Any);if (result == SCardError.Success){var protocol = reader.ActiveProtocol;return $"连接测试成功!\n读卡器: {readerName}\n协议: {protocol}";}else{return $"连接测试失败: {SCardHelper.StringifyError(result)}";}}catch (Exception ex){return $"连接测试异常: {ex.Message}";}});}#endregion#region 私有方法/// <summary>/// 获取第一个可用的读卡器/// </summary>/// <param name="context">PC/SC上下文</param>/// <returns>读卡器名称</returns>/// <exception cref="InvalidOperationException">当没有可用读卡器时抛出</exception>private string GetFirstAvailableReader(SCardContext context){var readerNames = context.GetReaders();if (readerNames.Length == 0)throw new InvalidOperationException("未检测到任何读卡器,请确认读卡器已正确连接");return readerNames[0];}/// <summary>/// 连接到卡片/// </summary>/// <param name="reader">读卡器实例</param>/// <param name="readerName">读卡器名称</param>/// <exception cref="InvalidOperationException">当连接失败时抛出</exception>private void ConnectToCard(SCardReader reader, string readerName){var result = reader.Connect(readerName, SCardShareMode.Shared, SCardProtocol.Any);if (result != SCardError.Success){throw new InvalidOperationException($"连接到读卡器失败: {SCardHelper.StringifyError(result)}。" +"请确认卡片已正确放置在读卡器上");}}/// <summary>/// 读取卡片UID/// </summary>/// <param name="reader">读卡器实例</param>/// <returns>UID字节数组</returns>/// <exception cref="InvalidOperationException">当读取失败时抛出</exception>private byte[] ReadCardUid(SCardReader reader){var receivePci = new SCardPCI();var sendPci = SCardPCI.GetPci(reader.ActiveProtocol);var receiveBuffer = new byte[RECEIVE_BUFFER_SIZE];var transmitResult = reader.Transmit(sendPci,GET_UID_COMMAND,receivePci,ref receiveBuffer);if (transmitResult != SCardError.Success){throw new InvalidOperationException($"发送UID读取命令失败: {SCardHelper.StringifyError(transmitResult)}");}// 提取有效的UID数据(去除填充的0x00)var uid = receiveBuffer.TakeWhile(b => b != 0x00).ToArray();if (uid.Length == 0 || uid.Length < 4){throw new InvalidOperationException("读取到的UID无效或长度不足");}return uid;}/// <summary>/// 尝试读取额外的卡片信息/// </summary>/// <param name="reader">读卡器实例</param>/// <returns>额外信息字符串</returns>private string TryReadAdditionalCardInfo(SCardReader reader){try{// 尝试读取更多信息的示例命令var infoCommand = new byte[] { 0xFF, 0xB0, 0x00, 0x00, 0x10 };var receivePci = new SCardPCI();var sendPci = SCardPCI.GetPci(reader.ActiveProtocol);var receiveBuffer = new byte[RECEIVE_BUFFER_SIZE];var result = reader.Transmit(sendPci,infoCommand,receivePci,ref receiveBuffer);if (result == SCardError.Success){var responseData = receiveBuffer.TakeWhile(b => b != 0x00).ToArray();if (responseData.Length > 0){return $"附加信息: {BitConverter.ToString(responseData)}";}}return "附加信息: 无法读取或不支持";}catch (Exception ex){return $"附加信息: 读取异常 ({ex.Message})";}}/// <summary>/// 检查指定读卡器中是否有卡片/// </summary>/// <param name="context">PC/SC上下文</param>/// <param name="readerName">读卡器名称</param>/// <returns>卡片状态描述</returns>private string CheckCardPresence(SCardContext context, string readerName){try{using var reader = new SCardReader(context);var connectResult = reader.Connect(readerName, SCardShareMode.Shared, SCardProtocol.Any);if (connectResult == SCardError.Success){return "有卡 (已连接)";}else if (connectResult == SCardError.NoSmartcard){return "无卡";}else{return $"未知状态 ({SCardHelper.StringifyError(connectResult)})";}}catch (Exception){return "检查失败";}}/// <summary>/// 格式化UID为可读字符串/// </summary>/// <param name="uid">UID字节数组</param>/// <returns>格式化的UID字符串</returns>private string FormatUid(byte[] uid){if (uid == null || uid.Length == 0)return "UID: 无效";var uidString = BitConverter.ToString(uid).Replace("-", ":");return $"UID: {uidString} (长度: {uid.Length} 字节)";}/// <summary>/// 执行带重试机制的异步操作/// </summary>/// <param name="operation">要执行的操作</param>/// <returns>操作结果</returns>private async Task<string> ExecuteWithRetryAsync(Func<Task<string>> operation){Exception lastException = null;for (int attempt = 1; attempt <= MAX_RETRY_COUNT; attempt++){try{return await operation();}catch (Exception ex){lastException = ex;if (attempt == MAX_RETRY_COUNT)break;// 在重试之间添加递增延迟await Task.Delay(RETRY_DELAY_BASE * attempt);}}// 如果所有重试都失败,返回错误信息return $"操作失败 (重试 {MAX_RETRY_COUNT} 次): {lastException?.Message ?? "未知错误"}";}#endregion#region 资源清理/// <summary>/// 清理资源/// </summary>public void Dispose(){// 强制垃圾回收,释放未管理资源GC.Collect();}#endregion}#region 扩展类和数据结构/// <summary>/// ICOCA卡信息结构/// </summary>public class IcocaCardInfo{public string Uid { get; set; } = string.Empty;public int Balance { get; set; }public DateTime LastUsed { get; set; }public List<TransactionRecord> History { get; set; } = new List<TransactionRecord>();}/// <summary>/// 交易记录结构/// </summary>public class TransactionRecord{public DateTime Date { get; set; }public string Type { get; set; } = string.Empty;public int Amount { get; set; }public string Station { get; set; } = string.Empty;}#endregion
}

 


using System;
using System.Linq;
using System.Threading.Tasks;
using PCSC;
using PCSC.Utils;namespace StarMauiPrinter.Services
{public class FelicaReaderService{/// <summary>/// 获取卡的 IDm(UID)、System Code,并根据 IDm 前缀推断卡类型/// </summary>public async Task<string?> GetCardInfoAsync(){try{using var context = ContextFactory.Instance.Establish(SCardScope.System);var readers = context.GetReaders();if (readers == null || readers.Length == 0)return "未检测到读卡器";var readerName = readers[0];using var reader = new SCardReader(context);var conn = reader.Connect(readerName, SCardShareMode.Shared, SCardProtocol.Any);if (conn != SCardError.Success)return $"连接失败: {SCardHelper.StringifyError(conn)}";var sendPci = SCardPCI.GetPci(reader.ActiveProtocol);var recvPci = new SCardPCI();var buffer = new byte[256];// 发送 Polling 命令以获取卡信息var polling = new byte[] {0xFF, 0x00, 0x00, 0x00, 0x04,0xD4, 0x04, 0x00, 0x01};var result = reader.Transmit(sendPci, polling, recvPci, ref buffer);if (result != SCardError.Success)return $"轮询失败: {SCardHelper.StringifyError(result)}";var response = buffer.TakeWhile(b => b != 0x00).ToArray();if (response.Length < 18)return "响应数据不足,无法解析卡片信息";var idm = response.Skip(9).Take(8).ToArray();var idmStr = BitConverter.ToString(idm);var idPrefix = $"{idm[0]:X2}-{idm[1]:X2}";var systemCode = response.Length >= 27 ? response.Skip(25).Take(2).ToArray() : new byte[] { 0x00, 0x00 };var sysCodeStr = $"{systemCode[0]:X2}{systemCode[1]:X2}";// 根据 IDm 前缀 和 System Code 判断卡种string cardType = sysCodeStr switch{"0003" => idPrefix switch{"01-01" or "02-01" => "Suica","03-01" => "PASMO","07-01" or "07-02" => "ICOCA",_ => "未知交通卡"},"FE00" or "FE01" => "Edy","8B01" => "WAON",_ => $"未知卡片(SystemCode: {sysCodeStr}, IDm前缀: {idPrefix})"};return $"卡类型: {cardType}\nIDm: {idmStr}\nSystem Code: {sysCodeStr}";}catch (Exception ex){return $"异常: {ex.Message}";}}}
}

相关文章:

随笔20250530 C# 整合 IC卡读写技术解析与实现

以下是一个完整、最简化的 FeliCa 读取整合示例&#xff08;无需 SDK&#xff0c;基于 PCSC NuGet 包&#xff09;&#xff0c;你可以直接运行这个控制台程序&#xff0c;验证能否识别 RC-S300 并读取卡片 UID&#xff1a; &#x1f9ea; 示例说明 &#x1f4e6; 使用 NuGet 包…...

循环神经网络(RNN):为什么它能处理时序数据?它真的能减轻过拟合吗?

循环神经网络&#xff08;RNN&#xff09;&#xff1a;为什么它能处理时序数据&#xff1f;它真的能减轻过拟合吗&#xff1f; 在深度学习领域&#xff0c;循环神经网络&#xff08;RNN, Recurrent Neural Network&#xff09;是一种非常重要的神经网络结构&#xff0c;尤其适…...

JVM与JMM深度解析:从Java 8到Java 21的演进

文章目录 第一部分&#xff1a;JVM基础概念与架构JVM是什么&#xff1f;JVM整体架构运行时数据区类加载机制执行引擎 第二部分&#xff1a;Java内存模型&#xff08;JMM&#xff09;什么是Java内存模型JMM的核心问题主内存与工作内存内存间交互操作重排序与happens-before原则v…...

基于爬取的典籍数据重新设计前端界面

1.BooksView(书籍列表页) 2.ClassicsView&#xff08;目录页&#xff09; 3.管理员端...

基于C++的IOT网关和平台5:github项目ctGateway开发指南

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。 源码指引:github源码指引_初级代码游戏的博客-CSDN博客 系…...

揭秘 NextJS Script 组件

揭秘 NextJS Script 组件 Next.js 的 Script 组件是对原生 <script> 标签的增强封装&#xff0c;主要区别和优势如下&#xff1a; 自动优化加载策略&#xff08;支持按需/延迟加载&#xff09;避免重复加载内置性能优化&#xff08;如预加载、回调钩子&#xff09;简化…...

网络安全防御指南:全方位抵御暴力破解攻击

在数字化时代&#xff0c;网络安全威胁如影随形&#xff0c;暴力破解攻击&#xff08;又称“爆破”&#xff09;作为黑客常用的入侵手段&#xff0c;正时刻觊觎着系统的薄弱环节。想象一下&#xff0c;攻击者如同不知疲倦的“数字小偷”&#xff0c;利用自动化工具疯狂尝试成千…...

【C++/Linux】TinyWebServer前置知识之IP协议详解

目录 IPv4地址 分类 IP数据报分片 IP 协议在传输数据报时&#xff0c;将数据报分为若干分片&#xff08;小数据报&#xff09;后进行传输&#xff0c;并在目的系统中进行重组&#xff0c;这一过程称为分片&#xff08;Fragmentation&#xff09;。 IP模块工作流程​编辑 I…...

mac安装brew时macos无法信任ruby的解决方法

背景 在使用如下脚本安装brew时&#xff0c;遇到安装ruby&#xff0c;macos不信任外部软件&#xff0c;在安全性点击信任仍然无法安装。 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"如何解决 本地安装好符…...

Codeforces Round 1028 (Div. 2)(A-D)

题面链接&#xff1a;Dashboard - Codeforces Round 1028 (Div. 2) - Codeforces A. Gellyfish and Tricolor Pansy 思路 要知道骑士如果没了那么这个人就失去了攻击手段&#xff0c;贪心的来说我们只需要攻击血量少的即可&#xff0c;那么取min比较一下即可 代码 void so…...

记录一个梦,借助大语言模型图片生成

梦见家门口有一条大河&#xff0c;但大河和其它景物都是灰暗没有鲜艳色彩很普通的梦中场景。大河似乎是长江的支流&#xff0c;但也可能有一个响亮的名字似乎是金沙江。 突然看到一条金红色的龙在快速游动&#xff0c;不敢相信自己的眼睛&#xff0c;因为一直不相信有这种生物…...

android binder(二)应用层编程实例

一、binder驱动浅析 从上图看出&#xff0c;binder的通讯主要涉及三个步骤。 在 Binder Server 端定义好服务&#xff0c;然后向 ServiceManager 注册服务在 Binder Client 中向 ServiceManager 获取到服务发起远程调用&#xff0c;调用 Binder Server 中定义好的服务 整个流…...

HTML 等价字符引用:系统化记忆指南

HTML 等价字符引用:系统化记忆指南 在 HTML 中,字符引用(Character Entity References)用于表示保留字符或特殊符号。我将提供一个系统化的方法来记忆这些重要实体,并解释它们的实际应用。 什么是等价字符引用? HTML 字符引用有两种形式: 命名实体:&entity_name…...

【深度学习】17. 深度生成模型:DCGAN与Wasserstein GAN公式深度推导

深度生成模型:DCGAN与Wasserstein GAN公式深度推导 深度卷积生成对抗网络 DCGAN 在原始 GAN 框架中&#xff0c;生成器和判别器通常使用全连接层构建&#xff0c;这限制了模型处理图像的能力。为此&#xff0c;Radford 等人在 2016 年提出了 DCGAN&#xff08;Deep Convoluti…...

Ubuntu终端性能监视工具

目录 工具1&#xff1a;nvidia-smi 工具2&#xff1a;nvtop 工具3&#xff1a;nvitop 工具1&#xff1a;nvidia-smi nvidia-smi 如果希望自动刷新这个命令&#xff0c;可以输入如下命令&#xff1a; nvidia-smi -l 工具2&#xff1a;nvtop nvtop 安装方法&#xff1a; …...

设计模式——命令设计模式(行为型)

摘要 本文介绍了命令设计模式&#xff0c;这是一种行为型设计模式&#xff0c;用于将请求封装为对象&#xff0c;实现请求的解耦和灵活控制。它包含命令接口、具体命令、接收者、调用者和客户端等角色&#xff0c;优点是解耦请求发送者与接收者&#xff0c;支持命令的排队、记…...

鸿蒙OSUniApp智能商品展示实战:打造高性能的动态排序系统#三方框架 #Uniapp

UniApp智能商品展示实战&#xff1a;打造高性能的动态排序系统 引言 在电商应用开发中&#xff0c;商品展示和智能排序是提升用户体验的关键因素。随着HarmonyOS生态的发展&#xff0c;用户对应用的性能和交互体验要求越来越高。本文将深入探讨如何在UniApp中实现一个性能优异…...

03 APP 自动化-定位元素工具元素定位

文章目录 一、Appium常用元素定位工具1、U IAutomator View Android SDK 自带的定位工具2、Appium Desktop Inspector3、Weditor安装&#xff1a;Weditor工具的使用 4、uiautodev通过定位工具获取app页面元素有哪些属性 二、app 元素定位方法 一、Appium常用元素定位工具 1、U…...

PABD 2025:大数据与智慧城市管理的融合之道

会议简介 2025年公共管理与大数据国际会议&#xff08;ICPMBD 2025&#xff09;确实在海口举办。本次会议将围绕公共管理与大数据的深度融合、数据分析在公共管理中的应用、大数据驱动的政策制定与优化等议题展开深入研讨。参会者将有机会聆听前沿学术报告&#xff0c;分享研究…...

Golang持续集成与自动化测试和部署

概述 Golang是一门性能优异的静态类型语言&#xff0c;但因其奇快的编译速度&#xff0c;结合DevOps, 使得它也非常适合快速开发和迭代。 本文讲述如何使用Golang, 进行持续集成与自动化测试和部署。主要使用了以下相关技术&#xff1a; dep&#xff1a; 进行包的依赖管理gin…...

三套知识系统的实践比较:Notion、Confluence 与 Gitee Wiki

在过去几年中&#xff0c;我们团队先后使用过三套企业知识系统&#xff1a;Notion、Confluence 和 Gitee Wiki。每一套系统上线初期都带来一阵热情&#xff0c;但最终能真正融入研发流程、持续活跃的&#xff0c;只有最后一个。 我们不是要为某个平台背书&#xff0c;而是希望…...

mysql离线安装教程

1.下载地址: https://downloads.mysql.com/archives/community/ 2.上传安装包到系统目录,并解压 tar -xvf mysql-8.0.34-1.el7.x86_64.rpm-bundle.tar3.检查系统中是否存在mariadb的rpm包 rpm -qa|grep mariadb存在则删除 rpm -e xxx4.解压完后执行如下命令安装 sudo rpm -iv…...

OpenGL 3D 编程

OpenGL 是一个强大的跨平台图形 API,用于渲染 2D 和 3D 图形。以下是 OpenGL 3D 编程的入门基础。 一. 环境设置 安装必要的库 GLFW: 用于创建窗口和处理输入 GLEW 或 GLAD: 用于加载 OpenGL 函数 GLM: 数学库,用于 3D 变换 // 基本 OpenGL 程序结构示例 #include <GL/g…...

基于FPGA的VGA显示文字和动态数字基础例程,进而动态显示数据,类似温湿度等

基于FPGA的VGA显示文字和数字 前言一、VGA显示参数二、字模生成三、代码分析1.vga_char顶层2.vga_ctrl驱动文件3.vga_pic数据准备文件 总结 前言 结合正点原子以及野火的基础例程&#xff0c;理解了VGA本身基本协议&#xff0c;VGA本身显示像素为640*480&#xff0c;因此注意生…...

力扣刷题Day 68:搜索插入位置(35)

1.题目描述 2.思路 方法1&#xff1a;回溯的二分查找。 方法2&#xff1a;看到了一个佬很简洁的写法&#xff0c;代码贴在下面了。 3.代码&#xff08;Python3&#xff09; 方法1&#xff1a; class Solution:def searchInsert(self, nums: List[int], target: int) ->…...

NodeJS全栈WEB3面试题——P4Node.js后端集成 服务端设计

4.1 如何在 Node.js 中管理钱包与私钥的安全性&#xff1f; 私钥管理原则&#xff1a;不暴露&#xff0c;不硬编码&#xff0c;不明文存储。 常见做法&#xff1a; 加密存储&#xff1a; 使用 crypto 或 ethers.Wallet.encrypt() 加密私钥&#xff0c;存储到数据库或文件系统…...

SQL进阶之旅 Day 12:分组聚合与HAVING高效应用

【SQL进阶之旅 Day 12】分组聚合与HAVING高效应用 在SQL的世界里&#xff0c;分组聚合&#xff08;Grouping and Aggregation&#xff09;是处理大规模数据集时最常用的技术之一。它允许我们将数据按照某些列进行分类&#xff0c;并对每个分类进行统计计算。而 HAVING 子句则是…...

深入剖析C#构造函数执行:基类调用、初始化顺序与访问控制

导言 在面向对象编程中&#xff0c;理解对象构造过程至关重要。C#的构造函数执行遵循严格的顺序规则&#xff0c;尤其是涉及继承和成员初始化时。本文将深入解析构造函数的执行流程、初始化语句的妙用以及类访问修饰符的影响&#xff0c;助你写出更健壮、可维护的代码。 构造…...

Java 大数据处理:使用 Hadoop 和 Spark 进行大规模数据处理

Java 大数据处理:使用 Hadoop 和 Spark 进行大规模数据处理 在当今数字化时代,数据呈现出爆炸式增长,如何高效地处理大规模数据成为企业面临的重要挑战。Java 作为一门广泛使用的编程语言,在大数据处理领域同样发挥着关键作用。本文将深入探讨如何利用 Hadoop 和 Spark 这…...

使用Python绘制节日祝福——以端午节和儿童节为例

端午节 端午节总算是回家了&#xff0c;感觉时间过得真快&#xff0c;马上就毕业了&#xff0c;用Python弄了一个端午节元素的界面&#xff0c;虽然有点不像&#xff0c;祝大家端午安康。端午节粽子&#xff08;python&#xff09;_python画粽子-CSDN博客https://blog.csdn.net…...