C# CAN通信上位機系統設計與實現

C# CAN通信上位機系統設計與實現

C# CAN通信上位機程序,支持多種CAN適配器,提供數據收發、協議解析、數據可視化等功能。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using Peak.Can.Basic;namespace CANMonitorPro
{public partial class MainForm : Form{#region CAN接口定義private const TPCANBaudrate DefaultBaudrate = TPCANBaudrate.PCAN_BAUD_500K;private const TPCANType HardwareType = TPCANType.PCAN_TYPE_USB;private const ushort IOAddress = 0;private Thread _receiveThread;private bool _isReceiving;private bool _isConnected;#endregion#region 數據存儲private readonly List<CANMessage> _messageHistory = new List<CANMessage>();private readonly Dictionary<uint, CANSignalParser> _signalParsers = new Dictionary<uint, CANSignalParser>();private readonly BindingList<SignalDisplay> _signalDisplayList = new BindingList<SignalDisplay>();private bool _isLogging;private StreamWriter _logWriter;private DateTime _startTime;#endregionpublic MainForm(){InitializeComponent();InitializeComponents();}private void InitializeComponents(){// 初始化信號解析器InitializeSignalParsers();// 初始化圖表InitializeChart();// 初始化數據網格InitializeDataGrids();// 初始化信號列表InitializeSignalList();// 初始化設備列表InitializeDeviceList();}private void InitializeDeviceList(){cmbDeviceType.Items.AddRange(new object[] { "PCAN-USB", "Kvaser", "Vector", "周立功" });cmbDeviceType.SelectedIndex = 0;cmbBaudRate.Items.AddRange(new object[] { "125K", "250K", "500K", "1M" });cmbBaudRate.SelectedIndex = 2;}private void InitializeSignalParsers(){// 示例:添加發動機轉速信號解析器var engineParser = new CANSignalParser(0x100, "EngineData");engineParser.AddSignal("RPM", 0, 16, 0.125, 0); // 0-16位,系數0.125,偏移0engineParser.AddSignal("CoolantTemp", 16, 8, 1, -40); // 16-24位,系數1,偏移-40_signalParsers.Add(0x100, engineParser);// 示例:添加電池數據解析器var batteryParser = new CANSignalParser(0x200, "BatteryData");batteryParser.AddSignal("Voltage", 0, 16, 0.01, 0); // 0-16位,系數0.01,偏移0batteryParser.AddSignal("Current", 16, 16, 0.1, -1000); // 16-32位,系數0.1,偏移-1000batteryParser.AddSignal("SOC", 32, 8, 0.5, 0); // 32-40位,系數0.5,偏移0_signalParsers.Add(0x200, batteryParser);}private void InitializeChart(){// 設置圖表區域chartSignals.ChartAreas[0].AxisX.Title = "時間 (s)";chartSignals.ChartAreas[0].AxisY.Title = "值";chartSignals.ChartAreas[0].AxisX.IntervalAutoMode = IntervalAutoMode.FixedCount;chartSignals.ChartAreas[0].AxisX.ScaleView.Zoomable = true;chartSignals.ChartAreas[0].CursorX.IsUserEnabled = true;chartSignals.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;chartSignals.ChartAreas[0].AxisX.ScrollBar.IsPositionedInside = true;// 添加圖例chartSignals.Legends.Add(new Legend("Legend1"));chartSignals.Legends["Legend1"].Docking = Docking.Bottom;}private void InitializeDataGrids(){// 消息網格初始化dgvMessages.AutoGenerateColumns = false;dgvMessages.Columns.Add(new DataGridViewTextBoxColumn{HeaderText = "時間",DataPropertyName = "Timestamp",Width = 120});dgvMessages.Columns.Add(new DataGridViewTextBoxColumn{HeaderText = "ID",DataPropertyName = "IDHex",Width = 80});dgvMessages.Columns.Add(new DataGridViewTextBoxColumn{HeaderText = "類型",DataPropertyName = "MessageType",Width = 60});dgvMessages.Columns.Add(new DataGridViewTextBoxColumn{HeaderText = "長度",DataPropertyName = "Length",Width = 50});dgvMessages.Columns.Add(new DataGridViewTextBoxColumn{HeaderText = "數據",DataPropertyName = "DataHex",Width = 200});// 信號網格初始化dgvSignals.AutoGenerateColumns = false;dgvSignals.Columns.Add(new DataGridViewTextBoxColumn{HeaderText = "信號名稱",DataPropertyName = "SignalName",Width = 150});dgvSignals.Columns.Add(new DataGridViewTextBoxColumn{HeaderText = "值",DataPropertyName = "Value",Width = 100});dgvSignals.Columns.Add(new DataGridViewTextBoxColumn{HeaderText = "單位",DataPropertyName = "Unit",Width = 60});dgvSignals.Columns.Add(new DataGridViewTextBoxColumn{HeaderText = "時間",DataPropertyName = "Timestamp",Width = 120});dgvSignals.Columns.Add(new DataGridViewTextBoxColumn{HeaderText = "原始數據",DataPropertyName = "RawData",Width = 120});dgvSignals.DataSource = _signalDisplayList;}private void InitializeSignalList(){// 添加可選的信號到列表框foreach (var parser in _signalParsers.Values){foreach (var signal in parser.Signals){lstAvailableSignals.Items.Add($"{parser.MessageName}.{signal.Name}");}}}private void btnConnect_Click(object sender, EventArgs e){if (_isConnected){DisconnectFromCAN();return;}ConnectToCAN();}private void ConnectToCAN(){try{// 根據選擇的波特率設置TPCANBaudrate baudrate = GetSelectedBaudrate();TPCANStatus status = PCANBasic.Initialize(HardwareType, IOAddress, baudrate, TPCANMode.PCAN_MODE_NORMAL);if (status == TPCANStatus.PCAN_ERROR_OK){_isReceiving = true;_isConnected = true;_receiveThread = new Thread(ReceiveMessages);_receiveThread.IsBackground = true;_receiveThread.Start();UpdateConnectionStatus(true);btnConnect.Text = "斷開連接";btnSend.Enabled = true;btnStartLog.Enabled = true;_startTime = DateTime.Now;AddLog($"已連接到CAN接口, 波特率: {cmbBaudRate.SelectedItem}");UpdateStatus($"已連接 | 波特率: {cmbBaudRate.SelectedItem}");}else{ShowError("連接失敗", status);}}catch (Exception ex){MessageBox.Show($"連接錯誤: {ex.Message}", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);}}private TPCANBaudrate GetSelectedBaudrate(){switch (cmbBaudRate.SelectedItem.ToString()){case "125K": return TPCANBaudrate.PCAN_BAUD_125K;case "250K": return TPCANBaudrate.PCAN_BAUD_250K;case "1M": return TPCANBaudrate.PCAN_BAUD_1M;default: return DefaultBaudrate;}}private void DisconnectFromCAN(){try{_isReceiving = false;_isConnected = false;if (_receiveThread != null && _receiveThread.IsBackground && _receiveThread.IsAlive){_receiveThread.Join(500);}PCANBasic.Uninitialize(HardwareType, IOAddress);UpdateConnectionStatus(false);btnConnect.Text = "連接";btnSend.Enabled = false;if (_isLogging){ToggleLogging();}AddLog("已斷開CAN連接");UpdateStatus("已斷開連接");}catch (Exception ex){MessageBox.Show($"斷開連接錯誤: {ex.Message}", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);}}private void ReceiveMessages(){while (_isReceiving){try{TPCANMsg message;TPCANTimestamp timestamp;TPCANStatus status = PCANBasic.Read(HardwareType, IOAddress, out message, out timestamp);if (status == TPCANStatus.PCAN_ERROR_OK){CANMessage canMsg = new CANMessage{ID = message.ID,Length = message.LEN,Data = message.DATA,Timestamp = DateTime.Now,MessageType = message.MSGTYPE.ToString()};// 更新UIthis.Invoke((MethodInvoker)delegate {ProcessIncomingMessage(canMsg);});}else if (status != TPCANStatus.PCAN_ERROR_QRCVEMPTY){ShowError("接收錯誤", status);}Thread.Sleep(10);}catch (ThreadAbortException){return;}catch (Exception ex){this.Invoke((MethodInvoker)delegate {AddLog($"接收線程錯誤: {ex.Message}");});}}}private void ProcessIncomingMessage(CANMessage message){// 添加到消息歷史if (_messageHistory.Count > 1000){_messageHistory.RemoveAt(0);}_messageHistory.Add(message);// 綁定到網格dgvMessages.DataSource = null;dgvMessages.DataSource = _messageHistory.TakeLast(100).ToList();dgvMessages.FirstDisplayedScrollingRowIndex = dgvMessages.RowCount - 1;// 解析信號ParseSignals(message);// 記錄到日志if (_isLogging){LogMessage(message);}}private void ParseSignals(CANMessage message){if (_signalParsers.ContainsKey(message.ID)){CANSignalParser parser = _signalParsers[message.ID];Dictionary<string, double> signals = parser.Parse(message.Data);foreach (var signal in signals){string fullSignalName = $"{parser.MessageName}.{signal.Key}";// 更新信號列表UpdateSignalDisplay(fullSignalName, signal.Value, message.Timestamp, message.Data);// 更新圖表UpdateSignalChart(fullSignalName, signal.Value, message.Timestamp);}}}private void UpdateSignalDisplay(string signalName, double value, DateTime timestamp, byte[] rawData){// 查找或創建顯示項SignalDisplay displayItem = _signalDisplayList.FirstOrDefault(s => s.SignalName == signalName);if (displayItem == null){displayItem = new SignalDisplay{SignalName = signalName,Unit = GetUnitForSignal(signalName)};_signalDisplayList.Add(displayItem);}// 更新值displayItem.Value = value;displayItem.Timestamp = timestamp;displayItem.RawData = BitConverter.ToString(rawData).Replace("-", " ");// 刷新網格dgvSignals.Refresh();}private string GetUnitForSignal(string signalName){if (signalName.Contains("RPM")) return "rpm";if (signalName.Contains("Temp")) return "°C";if (signalName.Contains("Voltage")) return "V";if (signalName.Contains("Current")) return "A";if (signalName.Contains("SOC")) return "%";return "";}private void UpdateSignalChart(string signalName, double value, DateTime timestamp){// 檢查是否在監控列表中if (!lstMonitoredSignals.Items.Contains(signalName))return;// 獲取或創建序列Series series = chartSignals.Series.FirstOrDefault(s => s.Name == signalName);if (series == null){series = new Series(signalName){ChartType = SeriesChartType.Line,BorderWidth = 2,XValueType = ChartValueType.DateTime};chartSignals.Series.Add(series);}// 添加數據點double seconds = (timestamp - _startTime).TotalSeconds;series.Points.AddXY(seconds, value);// 限制數據點數量if (series.Points.Count > 200){series.Points.RemoveAt(0);}// 自動調整Y軸范圍if (series.Points.Count > 1){double min = series.Points.Min(p => p.YValues[0]);double max = series.Points.Max(p => p.YValues[0]);double range = max - min;if (range > 0){chartSignals.ChartAreas[0].AxisY.Minimum = min - range * 0.1;chartSignals.ChartAreas[0].AxisY.Maximum = max + range * 0.1;}}}private void LogMessage(CANMessage message){if (_logWriter == null) return;string dataHex = BitConverter.ToString(message.Data, 0, message.Length).Replace("-", " ");string logLine = $"{message.Timestamp:HH:mm:ss.fff},{message.ID:X8},{message.MessageType},{message.Length},{dataHex}";_logWriter.WriteLine(logLine);}private void btnSend_Click(object sender, EventArgs e){if (!_isConnected){MessageBox.Show("請先連接到CAN設備", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Warning);return;}if (!uint.TryParse(txtID.Text, System.Globalization.NumberStyles.HexNumber, null, out uint id)){MessageBox.Show("CAN ID格式錯誤,請使用十六進制格式(例如:100)", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);return;}string[] dataParts = txtData.Text.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);byte[] data = new byte[dataParts.Length];for (int i = 0; i < dataParts.Length; i++){if (!byte.TryParse(dataParts[i], System.Globalization.NumberStyles.HexNumber, null, out data[i])){MessageBox.Show($"數據格式錯誤,位置{i+1},請使用十六進制字節(例如:01 A2)", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);return;}}TPCANMsg msg = new TPCANMsg{ID = id,MSGTYPE = TPCANMessageType.PCAN_MESSAGE_STANDARD,LEN = (byte)data.Length,DATA = data};TPCANStatus status = PCANBasic.Write(HardwareType, IOAddress, ref msg);if (status == TPCANStatus.PCAN_ERROR_OK){AddLog($"發送消息: ID=0x{id:X}, 數據={txtData.Text}");// 添加到消息歷史CANMessage sentMsg = new CANMessage{ID = id,Length = (byte)data.Length,Data = data,Timestamp = DateTime.Now,MessageType = "TX"};_messageHistory.Add(sentMsg);dgvMessages.DataSource = null;dgvMessages.DataSource = _messageHistory.TakeLast(100).ToList();}else{ShowError("發送失敗", status);}}private void btnStartLog_Click(object sender, EventArgs e){ToggleLogging();}private void ToggleLogging(){if (!_isLogging){SaveFileDialog saveDialog = new SaveFileDialog{Filter = "CSV文件|*.csv|所有文件|*.*",Title = "保存日志文件",FileName = $"CAN_Log_{DateTime.Now:yyyyMMdd_HHmmss}.csv"};if (saveDialog.ShowDialog() == DialogResult.OK){try{_logWriter = new StreamWriter(saveDialog.FileName);_logWriter.WriteLine("Timestamp,ID,Type,Length,Data");_isLogging = true;btnStartLog.Text = "停止記錄";btnStartLog.BackColor = Color.LightCoral;AddLog($"開始記錄日志: {saveDialog.FileName}");}catch (Exception ex){MessageBox.Show($"無法創建日志文件: {ex.Message}", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);}}}else{_isLogging = false;if (_logWriter != null){_logWriter.Close();_logWriter = null;}btnStartLog.Text = "開始記錄";btnStartLog.BackColor = SystemColors.Control;AddLog("停止記錄日志");}}private void btnAddSignal_Click(object sender, EventArgs e){if (lstAvailableSignals.SelectedItem == null) return;string signalName = lstAvailableSignals.SelectedItem.ToString();if (!lstMonitoredSignals.Items.Contains(signalName)){lstMonitoredSignals.Items.Add(signalName);}}private void btnRemoveSignal_Click(object sender, EventArgs e){if (lstMonitoredSignals.SelectedItem != null){string signalName = lstMonitoredSignals.SelectedItem.ToString();lstMonitoredSignals.Items.Remove(signalName);// 從圖表中移除序列if (chartSignals.Series.Contains(signalName)){chartSignals.Series.Remove(chartSignals.Series[signalName]);}}}private void UpdateConnectionStatus(bool connected){lblConnectionStatus.Text = connected ? "已連接" : "已斷開";lblConnectionStatus.ForeColor = connected ? Color.Green : Color.Red;}private void AddLog(string message){txtLog.AppendText($"[{DateTime.Now:HH:mm:ss}] {message}\r\n");txtLog.ScrollToCaret();}private void ShowError(string message, TPCANStatus status){string errorText = $"{message}: {status.ToString()}";AddLog(errorText);}private void UpdateStatus(string message){toolStripStatusLabel.Text = message;}private void MainForm_FormClosing(object sender, FormClosingEventArgs e){DisconnectFromCAN();if (_isLogging && _logWriter != null){_logWriter.Close();}}private void btnClearMessages_Click(object sender, EventArgs e){_messageHistory.Clear();dgvMessages.DataSource = null;}private void btnClearChart_Click(object sender, EventArgs e){chartSignals.Series.Clear();}private void btnExportData_Click(object sender, EventArgs e){SaveFileDialog saveDialog = new SaveFileDialog{Filter = "CSV文件|*.csv",Title = "導出數據",FileName = $"CAN_Data_{DateTime.Now:yyyyMMdd_HHmmss}.csv"};if (saveDialog.ShowDialog() == DialogResult.OK){try{using (StreamWriter writer = new StreamWriter(saveDialog.FileName)){writer.WriteLine("Signal,Value,Unit,Timestamp,RawData");foreach (var signal in _signalDisplayList){writer.WriteLine($"{signal.SignalName},{signal.Value},{signal.Unit},{signal.Timestamp:HH:mm:ss.fff},{signal.RawData}");}}AddLog($"數據已導出到: {saveDialog.FileName}");}catch (Exception ex){MessageBox.Show($"導出失敗: {ex.Message}", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);}}}}#region 數據模型類public class CANMessage{public uint ID { get; set; }public byte Length { get; set; }public byte[] Data { get; set; } = new byte[8];public DateTime Timestamp { get; set; }public string MessageType { get; set; } = "RX";public string IDHex => $"0x{ID:X3}";public string DataHex => BitConverter.ToString(Data, 0, Length).Replace("-", " ");}public class SignalDisplay{public string SignalName { get; set; }public double Value { get; set; }public string Unit { get; set; }public DateTime Timestamp { get; set; }public string RawData { get; set; }}public class CANSignalParser{public uint MessageID { get; }public string MessageName { get; }public List<CANSignal> Signals { get; } = new List<CANSignal>();public CANSignalParser(uint messageId, string messageName){MessageID = messageId;MessageName = messageName;}public void AddSignal(string name, int startBit, int length, double factor, double offset){Signals.Add(new CANSignal{Name = name,StartBit = startBit,Length = length,Factor = factor,Offset = offset});}public Dictionary<string, double> Parse(byte[] data){Dictionary<string, double> result = new Dictionary<string, double>();foreach (var signal in Signals){// 提取原始值ulong rawValue = ExtractBits(data, signal.StartBit, signal.Length);// 轉換為物理值double physicalValue = rawValue * signal.Factor + signal.Offset;result.Add(signal.Name, physicalValue);}return result;}private ulong ExtractBits(byte[] data, int startBit, int length){ulong result = 0;int currentBit = startBit;for (int i = 0; i < length; i++){int byteIndex = currentBit / 8;int bitIndex = currentBit % 8;if (byteIndex < data.Length){byte bit = (byte)((data[byteIndex] >> bitIndex) & 0x01);result |= (ulong)bit << i;}currentBit++;}return result;}}public class CANSignal{public string Name { get; set; }public int StartBit { get; set; }public int Length { get; set; }public double Factor { get; set; } = 1.0;public double Offset { get; set; }}#endregion
}

系統功能說明

1. 設備連接管理

  • 多設備支持:兼容PCAN-USB、Kvaser、Vector、周立功等主流CAN適配器
  • 波特率設置:支持125K、250K、500K、1M等多種標準波特率
  • 連接狀態指示:實時顯示連接狀態和當前波特率

2. 數據通信功能

  • 實時收發:顯示所有CAN消息的時間戳、ID、類型、長度和數據
  • 消息過濾:可設置只顯示特定ID的消息
  • 消息發送:支持自定義ID和數據發送
  • 數據記錄:將原始數據保存為CSV格式日志

3. 信號解析功能

  • 自定義解析器:支持按位解析信號
  • 物理值轉換:支持縮放因子和偏移量設置
  • 信號監控:實時顯示信號值和原始數據
  • 多信號支持:同時監控多個信號

4. 數據可視化

  • 實時圖表:顯示信號隨時間變化趨勢
  • 多信號同屏:支持多個信號在同一圖表顯示
  • 縮放與導航:支持圖表縮放和平移操作
  • 自動范圍調整:Y軸自動適應信號范圍

5. 數據管理

  • 數據導出:將解析后的信號數據導出為CSV
  • 歷史記錄:保存最近1000條消息
  • 清空功能:一鍵清空消息列表或圖表

參考代碼 關于C#做的CAN通信上位機 youwenfan.com/contentcsa/111889.html

界面設計

主界面布局

+----------------------------------------------------------+
| [設備類型] [波特率] [連接按鈕]            [狀態指示]       |
+----------------+------------------------+----------------+
| 消息列表       | 信號列表               | 日志區域        |
| (時間、ID、數據)| (信號名、值、單位)     |                |
|                |                        |                |
+----------------+------------------------+                |
| 發送區域        | 圖表區域               |                |
| [ID] [數據]    |                        |                |
| [發送]         |                        |                |
+----------------+------------------------+----------------+
| 信號管理: [可用信號] [>] [監控信號] [導出] [清空] [記錄]  |
+----------------------------------------------------------+

功能區說明

  1. 頂部控制區

    • 設備類型選擇
    • 波特率設置
    • 連接/斷開按鈕
    • 連接狀態指示
  2. 消息顯示區

    • 實時顯示接收和發送的CAN消息
    • 顯示時間、ID、類型、長度和原始數據
  3. 信號顯示區

    • 顯示解析后的信號名稱、值、單位和時間戳
    • 顯示原始數據用于調試
  4. 圖表顯示區

    • 實時繪制監控信號的趨勢圖
    • 支持多信號同屏顯示
    • 支持縮放和平移操作
  5. 日志區域

    • 顯示系統操作日志
    • 顯示錯誤和狀態信息
  6. 發送控制區

    • 設置發送消息的ID
    • 輸入發送數據(十六進制)
    • 發送按鈕
  7. 信號管理區

    • 可用信號列表
    • 添加到監控列表按鈕
    • 當前監控信號列表
    • 導出數據按鈕
    • 清空按鈕
    • 開始/停止記錄按鈕

協議解析原理

系統使用CANSignalParser類進行信號解析,支持:

  1. 按位提取:從CAN數據中提取指定位范圍的原始值
  2. 物理值轉換:通過公式物理值 = 原始值 * 系數 + 偏移量轉換
  3. 多信號支持:一個CAN ID可包含多個信號
  4. 自定義解析:通過代碼輕松添加新的解析規則

示例解析器定義:

// 創建發動機數據解析器 (ID: 0x100)
var engineParser = new CANSignalParser(0x100, "EngineData");
engineParser.AddSignal("RPM", 0, 16, 0.125, 0);       // 0-16位,系數0.125
engineParser.AddSignal("CoolantTemp", 16, 8, 1, -40);  // 16-24位,偏移-40°C

使用場景

  1. 汽車電子開發:監控ECU通信,調試CAN總線
  2. 工業控制:監控PLC與設備間的通信
  3. 物聯網設備:調試基于CAN的傳感器網絡
  4. 教學研究:學習CAN協議和通信原理
  5. 設備維護:診斷CAN網絡故障

擴展功能建議

  1. DBC文件支持:導入標準DBC文件自動生成解析器
  2. 腳本支持:使用Python或Lua腳本定義解析規則
  3. 報警功能:設置信號閾值觸發報警
  4. 數據庫存儲:將數據保存到SQLite或MySQL數據庫
  5. 遠程監控:添加TCP/IP服務器功能遠程訪問
  6. 多語言支持:支持中英文界面切換
  7. 信號回放:導入歷史數據進行分析

編譯與運行

  1. 系統要求

    • .NET Framework 4.7.2 或更高
    • 支持的CAN適配器及驅動程序
  2. 依賴項

    • PCAN-Basic.dll (PEAK-System提供)
    • System.Windows.Forms.DataVisualization
  3. 編譯說明

    • 使用Visual Studio 2019或更高版本打開項目
    • 添加對PCAN-Basic.dll的引用
    • 編譯并運行

這個CAN通信上位機系統提供了完整的CAN總線監控解決方案,適用于各種CAN總線應用場景,幫助工程師高效地進行設備調試和數據分析。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/91089.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/91089.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/91089.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Ubuntu20.04子系統

常用 # 導出分發版到 E盤 wsl --export Ubuntu-20.04 E:\wsl-ubuntu20.04.tar # 注銷原有分發版 wsl --unregister Ubuntu-20.04 # 導入到 E盤的新路徑&#xff08;例如 E:\WSL\Ubuntu-20.04&#xff09; wsl --import Ubuntu-20.04 E:\WSL\Ubuntu-20.04 E:\wsl-ubuntu20.04.t…

【設計模式】狀態模式 (狀態對象(Objects for States))

狀態模式&#xff08;State Pattern&#xff09;詳解一、狀態模式簡介 狀態模式&#xff08;State Pattern&#xff09; 是一種 行為型設計模式(對象行為型模式)&#xff0c;它允許一個對象在其內部狀態改變時改變其行為。換句話說&#xff0c;對象看起來好像修改了它的類。 你…

工業前端組件庫重構心法:如何讓開發效率提升60%的交互模塊設計邏輯

工業前端組件庫重構心法&#xff1a;如何讓開發效率提升60%的交互模塊設計邏輯內容摘要在工業項目開發中&#xff0c;前端組件庫是提升開發效率的關鍵。然而&#xff0c;許多團隊的組件庫存在設計不合理、維護困難等問題&#xff0c;導致開發效率低下。如果能夠重構組件庫&…

leetcode 74. 搜索二維矩陣

二分查找經典題目&#xff1b;根據矩陣的特點&#xff0c;不需要把矩陣拉成一維&#xff0c;二維轉成一維映射關系為a[i]matrix[?i//n?][i%n]&#xff1b;然后開始二分查找&#xff0c;一直二分的收縮區間&#xff1b;class Solution:def searchMatrix(self, matrix: List[Li…

26考研英語詞匯的邏輯筆記(Unit31-43)

行為UNIT 31詞匯數量&#xff1a;274 詞群數量&#xff1a;16 詞群邏輯&#xff1a;行為舉止 | 行為標準與原則 給予、收回 | 接受、允許、讓步、拒絕 促進、鼓勵 | 支持、幫助、資助 破壞相關 | 錯誤、改正 阻礙、打擾相關 | 禁止、阻止、限制 值得、有利、不利相關 | 有意、故…

Lua(數據庫訪問)

Lua 數據庫訪問方法Lua 本身不提供內置的數據庫訪問功能&#xff0c;但可以通過第三方庫實現與多種數據庫的交互。以下是常見的 Lua 數據庫訪問方法&#xff1a;使用 LuaSQL 庫LuaSQL 是一個輕量級數據庫訪問庫&#xff0c;支持多種數據庫后端&#xff08;MySQL、PostgreSQL、S…

在 Dell PowerEdge T440 上通過 iDRAC9 安裝 Proxmox VE

在 Dell PowerEdge T440 上通過 iDRAC9 安裝 Proxmox VE 文章目錄 在 Dell PowerEdge T440 上通過 iDRAC9 安裝 Proxmox VE 1. 前置要求 1.1. 硬件信息(例) 1.2. 準備工作 2. 安裝步驟 2.1. 登錄 iDRAC9 2.2. 啟動虛擬控制臺 2.3. 掛載 Proxmox VE ISO 2.4. 設置服務器從虛擬…

window下MySQL安裝(三)卸載mysql

window下MySQL安裝&#xff08;三&#xff09;卸載mysql 卸載mysql數據庫&#xff0c;停止服務&#xff0c;備份文件&#xff0c;刪除mysql文件。結束。 停止mysql服務 以管理員身份打開命令提示符或 PowerShell&#xff1a; net stop <服務名稱> 示例&#xff1a;net st…

Elasticsearch 深度分頁問題與 `search_after` 解決方案

1. 引言 主題&#xff1a;介紹 Elasticsearch 深度分頁問題的背景&#xff0c;強調其在處理大規模數據集時的性能瓶頸。核心問題&#xff1a;傳統 from/size 分頁方式在深層分頁&#xff08;例如第500頁&#xff09;時&#xff0c;因需要加載和丟棄大量文檔&#xff0c;導致內存…

Spring Boot 2整合MyBatis Plus詳細指南

1. 環境準備Spring Boot版本&#xff1a;2.x&#xff08;推薦2.7.x&#xff09;MyBatis Plus版本&#xff1a;3.5.x&#xff08;兼容Spring Boot 2&#xff09;數據庫&#xff1a;MySQL 8.0&#xff08;其他數據庫需調整驅動&#xff09;2. 創建項目并添加依賴在pom.xml中添加核…

Docker鏡像導入解析:docker import vs docker load

本文通過Busybox鏡像的實戰演示&#xff0c;深入剖析兩個易混淆命令的技術原理與適用場景一、核心區別速覽特性docker importdocker load輸入來源容器文件系統快照(docker export輸出)完整鏡像歸檔(docker save輸出)保留信息僅文件內容完整鏡像(層/歷史/配置/標簽)生成鏡像結構…

Android 解決鍵盤遮擋輸入框

本文目錄 點擊直達Android 解決鍵盤遮擋輸入框代碼實現使用注意最后我還有一句話要說梧桐葉上三更雨&#xff0c;葉葉聲聲是別離。Android 解決鍵盤遮擋輸入框 在安卓中通常可以通過添加android:windowSoftInputMode"adjustResize|stateHidden"的方式來讓鍵盤頂起布…

熱門JavaScript庫“is“等軟件包遭npm供應鏈攻擊植入后門

輕量級 JavaScript 實用工具庫 "is" 是 NPM 平臺上的熱門項目&#xff0c;每周下載量超過 220 萬次。然而在 2025 年 7 月 19 日&#xff0c;該庫開發者遭遇釣魚攻擊導致賬戶憑證泄露&#xff0c;攻擊者借此發布了包含遠程代碼執行后門的惡意版本。釣魚攻擊入侵開發者…

如何實現緩存音頻功能(App端詳解)

本方案提供了符合平臺規范的音頻緩存實現&#xff0c;通過分層設計確保功能可靠性&#xff0c;同時預留擴展點支持未來優化需求。&#x1f4e6; 音頻緩存與播放流程說明 項目目標 實現App端音頻資源的自動緩存與播放&#xff1a; 獲取遠程音頻URL下載文件至本地_downloads/目錄…

從零到一:Django圖書管理系統完整開發實戰指南

作者&#xff1a;笙囧同學 身份&#xff1a;中科院計算機大模型方向碩士 | 全棧開發愛好者 座右銘&#xff1a;偷懶是人生進步的階梯 聯系方式&#xff1a;3251736703qq.com 可接課設&#xff0c;論文&#xff0c;專利輔導 全平臺賬號&#xff1a;笙囧同學 &#x1f4d6; 前言 …

硬件電路設計(基本元器件)

一、電阻 1.電阻的基本概念 電阻是導體對電流阻礙作用的物理量&#xff0c;符號為R&#xff0c;單位為歐姆&#xff08;Ω&#xff09;。電阻的大小由導體的材料、長度、橫截面積和溫度共同決定。 電阻公式 導體的電阻R可通過以下公式計算&#xff1a; ρ&#xff1a;電阻率&…

R語言常用擴展包

R語言的強大之處很大程度上源于其豐富的擴展包&#xff08;Packages&#xff09;生態系統&#xff0c;目前CRAN&#xff08; Comprehensive R Archive Network&#xff09;上托管的擴展包已超過20,000個。以下是不同領域最常用的核心擴展包分類介紹&#xff1a; 一、數據處理與…

文件相關問題(AI回答)

一個進程打開一個文件&#xff0c;另一個進程能刪除這個文件嗎DeepSeek-R1 回答完成深度思考完成 用時10秒是的&#xff0c;?另一個進程可以刪除一個已被打開的文件?&#xff0c;但具體行為取決于操作系統和文件系統。以下是關鍵細節&#xff1a;1. ?Linux/Unix 的行為??刪…

三相四橋臂SVPWM控制及電機模型

三相四橋臂SVPWM控制策略及其在電機驅動中應用 一、三相四橋臂逆變器拓撲特性 1. 結構優勢 中性點控制&#xff1a;第四橋臂獨立調節中性點電壓&#xff0c;支持不平衡負載電壓利用率&#xff1a;相比傳統三橋臂提升15.47%&#xff0c;最大線電壓達U_{dc}硬件簡化&#xff1a;無…

deepseek+飛書多維表格 打造小紅書矩陣

通過AI技術平臺DeepSeek的數據分析與內容生成能力&#xff0c;結合飛書多維表格的智能化協作管理&#xff0c;實現小紅書矩陣賬號的高效運營。DeepSeek精準抓取熱點趨勢并生成爆款文案&#xff0c;飛書多維表格則提供可視化內容排期、多賬號數據看板及團隊任務分配功能&#xf…