【PDF識別改名】使用京東云OCR完成PDF圖片識別改名,根據PDF圖片內容批量改名詳細步驟和解決方案

京東云OCR識別PDF圖片并批量改名解決方案

一、應用場景

在日常辦公和文檔管理中,經常會遇到大量 PDF 文件需要根據內容進行分類和命名的情況。例如:

  • 企業合同管理系統需要根據合同編號、日期等內容自動命名 PDF 文件
  • 圖書館數字化項目需要將掃描的圖書章節按照標題命名
  • 財務部門需要將發票 PDF 按照發票號碼、金額等信息自動歸類

京東云 OCR 提供了強大的文字識別能力,可以準確識別 PDF 中的文字信息,結合 C# 開發的桌面應用程序,可以實現高效的 PDF 批量改名工作流。

二、界面設計

一個直觀易用的界面設計可以提高工作效率,建議包含以下元素:

  1. 文件選擇區域:支持拖拽和文件選擇對話框選擇多個 PDF 文件
  2. OCR 配置區域:選擇 OCR 模板、設置識別語言等
  3. 預覽區域:顯示原始文件名、識別內容和建議的新文件名
  4. 處理進度條:顯示當前處理進度和狀態
  5. 操作按鈕:開始處理、取消、保存設置等
三、詳細代碼步驟解析
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using Newtonsoft.Json;
using RestSharp;namespace JdCloudOcrPdfRenameTool
{public partial class MainForm : Form{// 京東云OCR配置信息private string accessKeyId = "";private string secretAccessKey = "";private string serviceEndpoint = "https://ocr.jdcloud-api.com/v1/regions/cn-north-1";// 存儲待處理的PDF文件列表private List<string> pdfFiles = new List<string>();// 存儲處理結果private List<RenameItem> renameItems = new List<RenameItem>();public MainForm(){InitializeComponent();InitializeUI();}private void InitializeUI(){// 設置窗體基本屬性this.Text = "JDOCR_PDF圖片識別改名工具";this.Size = new Size(900, 600);this.StartPosition = FormStartPosition.CenterScreen;// 創建控件CreateFileSelectionPanel();CreateOcrConfigPanel();CreatePreviewPanel();CreateActionButtons();// 加載配置LoadSettings();}private Panel fileSelectionPanel;private TextBox txtSelectedFiles;private Button btnSelectFiles;private Button btnClearFiles;private void CreateFileSelectionPanel(){fileSelectionPanel = new Panel{Dock = DockStyle.Top,Height = 100,BorderStyle = BorderStyle.FixedSingle};Label lblFileSelection = new Label{Text = "選擇PDF文件:",Location = new Point(10, 10),AutoSize = true};txtSelectedFiles = new TextBox{Location = new Point(10, 30),Size = new Size(650, 23),ReadOnly = true};btnSelectFiles = new Button{Text = "選擇文件",Location = new Point(670, 30),Size = new Size(100, 23)};btnSelectFiles.Click += BtnSelectFiles_Click;btnClearFiles = new Button{Text = "清除",Location = new Point(780, 30),Size = new Size(100, 23)};btnClearFiles.Click += BtnClearFiles_Click;Label lblDragDrop = new Label{Text = "或者直接將PDF圖片識別文件拖放到此處...",Location = new Point(10, 60),ForeColor = Color.Gray};fileSelectionPanel.Controls.Add(lblFileSelection);fileSelectionPanel.Controls.Add(txtSelectedFiles);fileSelectionPanel.Controls.Add(btnSelectFiles);fileSelectionPanel.Controls.Add(btnClearFiles);fileSelectionPanel.Controls.Add(lblDragDrop);// 設置拖放功能fileSelectionPanel.AllowDrop = true;fileSelectionPanel.DragEnter += FileSelectionPanel_DragEnter;fileSelectionPanel.DragDrop += FileSelectionPanel_DragDrop;this.Controls.Add(fileSelectionPanel);}private Panel ocrConfigPanel;private TextBox txtAccessKey;private TextBox txtSecretKey;private ComboBox cboOcrTemplate;private CheckBox chkOverwrite;private TextBox txtNameFormat;private Button btnSaveSettings;private void CreateOcrConfigPanel(){ocrConfigPanel = new Panel{Dock = DockStyle.Top,Height = 150,BorderStyle = BorderStyle.FixedSingle};Label lblAccessKey = new Label{Text = "Access Key:",Location = new Point(10, 10),Size = new Size(80, 20)};txtAccessKey = new TextBox{Location = new Point(100, 10),Size = new Size(250, 23),Text = accessKeyId};Label lblSecretKey = new Label{Text = "Secret Key:",Location = new Point(10, 40),Size = new Size(80, 20)};txtSecretKey = new TextBox{Location = new Point(100, 40),Size = new Size(250, 23),Text = secretAccessKey,PasswordChar = '*'};Label lblOcrTemplate = new Label{Text = "OCR模板:",Location = new Point(10, 70),Size = new Size(80, 20)};cboOcrTemplate = new ComboBox{Location = new Point(100, 70),Size = new Size(250, 23),DropDownStyle = ComboBoxStyle.DropDownList};cboOcrTemplate.Items.AddRange(new string[] { "通用文字識別", "身份證識別", "營業執照識別", "增值稅發票識別" });cboOcrTemplate.SelectedIndex = 0;Label lblNameFormat = new Label{Text = "命名格式:",Location = new Point(380, 10),Size = new Size(80, 20)};txtNameFormat = new TextBox{Location = new Point(460, 10),Size = new Size(380, 23),Text = "{日期}_{關鍵詞}_{序號}"};Label lblFormatHelp = new Label{Text = "支持變量: {日期}, {時間}, {關鍵詞}, {頁碼}, {序號}, {原文件名}",Location = new Point(380, 40),Size = new Size(500, 20),ForeColor = Color.Gray,Font = new Font(Font, FontStyle.Italic)};chkOverwrite = new CheckBox{Text = "覆蓋已存在文件",Location = new Point(380, 70),Size = new Size(120, 20)};btnSaveSettings = new Button{Text = "保存設置",Location = new Point(740, 100),Size = new Size(100, 23)};btnSaveSettings.Click += BtnSaveSettings_Click;ocrConfigPanel.Controls.Add(lblAccessKey);ocrConfigPanel.Controls.Add(txtAccessKey);ocrConfigPanel.Controls.Add(lblSecretKey);ocrConfigPanel.Controls.Add(txtSecretKey);ocrConfigPanel.Controls.Add(lblOcrTemplate);ocrConfigPanel.Controls.Add(cboOcrTemplate);ocrConfigPanel.Controls.Add(lblNameFormat);ocrConfigPanel.Controls.Add(txtNameFormat);ocrConfigPanel.Controls.Add(lblFormatHelp);ocrConfigPanel.Controls.Add(chkOverwrite);ocrConfigPanel.Controls.Add(btnSaveSettings);this.Controls.Add(ocrConfigPanel);}private Panel previewPanel;private DataGridView dgvPreview;private ProgressBar progressBar;private Label lblProgress;private void CreatePreviewPanel(){previewPanel = new Panel{Dock = DockStyle.Fill,BorderStyle = BorderStyle.FixedSingle};dgvPreview = new DataGridView{Dock = DockStyle.Fill,AutoGenerateColumns = false,SelectionMode = DataGridViewSelectionMode.FullRowSelect,MultiSelect = false};// 添加列dgvPreview.Columns.Add(new DataGridViewTextBoxColumn{HeaderText = "序號",DataPropertyName = "Index",Width = 50});dgvPreview.Columns.Add(new DataGridViewTextBoxColumn{HeaderText = "原始文件名",DataPropertyName = "OriginalFileName",Width = 250});dgvPreview.Columns.Add(new DataGridViewTextBoxColumn{HeaderText = "識別內容",DataPropertyName = "OcrText",Width = 300});dgvPreview.Columns.Add(new DataGridViewTextBoxColumn{HeaderText = "新文件名",DataPropertyName = "NewFileName",Width = 250});dgvPreview.Columns.Add(new DataGridViewTextBoxColumn{HeaderText = "處理狀態",DataPropertyName = "Status",Width = 100});progressBar = new ProgressBar{Dock = DockStyle.Bottom,Height = 20,Visible = false};lblProgress = new Label{Dock = DockStyle.Bottom,Height = 20,TextAlign = ContentAlignment.MiddleLeft,Padding = new Padding(5, 0, 0, 0),Visible = false};previewPanel.Controls.Add(dgvPreview);previewPanel.Controls.Add(progressBar);previewPanel.Controls.Add(lblProgress);this.Controls.Add(previewPanel);}private Button btnProcess;private Button btnRename;private Button btnExport;private void CreateActionButtons(){Panel buttonPanel = new Panel{Dock = DockStyle.Bottom,Height = 40,BorderStyle = BorderStyle.FixedSingle};btnProcess = new Button{Text = "開始識別",Location = new Point(10, 7),Size = new Size(100, 23)};btnProcess.Click += BtnProcess_Click;btnRename = new Button{Text = "執行改名",Location = new Point(120, 7),Size = new Size(100, 23),Enabled = false};btnRename.Click += BtnRename_Click;btnExport = new Button{Text = "導出結果",Location = new Point(230, 7),Size = new Size(100, 23),Enabled = false};btnExport.Click += BtnExport_Click;buttonPanel.Controls.Add(btnProcess);buttonPanel.Controls.Add(btnRename);buttonPanel.Controls.Add(btnExport);this.Controls.Add(buttonPanel);}// 拖放事件處理private void FileSelectionPanel_DragEnter(object sender, DragEventArgs e){if (e.Data.GetDataPresent(DataFormats.FileDrop)){e.Effect = DragDropEffects.Copy;}}private void FileSelectionPanel_DragDrop(object sender, DragEventArgs e){string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);AddPdfFiles(files);}// 按鈕事件處理private void BtnSelectFiles_Click(object sender, EventArgs e){using (OpenFileDialog openFileDialog = new OpenFileDialog()){openFileDialog.Multiselect = true;openFileDialog.Filter = "PDF文件 (*.pdf)|*.pdf|所有文件 (*.*)|*.*";openFileDialog.Title = "選擇PDF文件";if (openFileDialog.ShowDialog() == DialogResult.OK){AddPdfFiles(openFileDialog.FileNames);}}}private void BtnClearFiles_Click(object sender, EventArgs e){pdfFiles.Clear();txtSelectedFiles.Text = "";UpdatePreviewGrid();}private void BtnSaveSettings_Click(object sender, EventArgs e){accessKeyId = txtAccessKey.Text.Trim();secretAccessKey = txtSecretKey.Text.Trim();SaveSettings();MessageBox.Show("設置已保存!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);}private async void BtnProcess_Click(object sender, EventArgs e){if (pdfFiles.Count == 0){MessageBox.Show("請先選擇PDF圖片識別文件!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);return;}if (string.IsNullOrEmpty(accessKeyId) || string.IsNullOrEmpty(secretAccessKey)){MessageBox.Show("請輸入JDXOCR的Access Key和Secret Key!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);return;}// 禁用按鈕防止重復點擊btnProcess.Enabled = false;btnRename.Enabled = false;progressBar.Visible = true;progressBar.Value = 0;progressBar.Maximum = pdfFiles.Count;lblProgress.Visible = true;// 清空之前的結果renameItems.Clear();// 異步處理PDF文件await ProcessPdfFilesAsync();// 更新界面UpdatePreviewGrid();// 恢復按鈕狀態btnProcess.Enabled = true;btnRename.Enabled = renameItems.Any(i => i.Status == "成功");progressBar.Visible = false;lblProgress.Visible = false;}private void BtnRename_Click(object sender, EventArgs e){if (renameItems.Count == 0 || !renameItems.Any(i => i.Status == "成功")){MessageBox.Show("沒有可處理的文件!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);return;}DialogResult result = MessageBox.Show($"確定要將{renameItems.Count(i => i.Status == "成功")}個文件重命名嗎?", "確認", MessageBoxButtons.YesNo, MessageBoxIcon.Question);if (result != DialogResult.Yes){return;}int successCount = 0;int failedCount = 0;foreach (var item in renameItems){if (item.Status != "成功"){continue;}try{string directory = Path.GetDirectoryName(item.FilePath);string newFilePath = Path.Combine(directory, item.NewFileName);// 檢查是否需要覆蓋if (File.Exists(newFilePath) && !chkOverwrite.Checked){item.Status = "已存在";failedCount++;continue;}File.Move(item.FilePath, newFilePath);item.Status = "已重命名";successCount++;}catch (Exception ex){item.Status = "失敗";item.ErrorMessage = ex.Message;failedCount++;}}UpdatePreviewGrid();MessageBox.Show($"重命名完成!成功: {successCount}, 失敗: {failedCount}", "結果", MessageBoxButtons.OK, MessageBoxIcon.Information);}private void BtnExport_Click(object sender, EventArgs e){if (renameItems.Count == 0){MessageBox.Show("沒有可導出的結果!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);return;}using (SaveFileDialog saveFileDialog = new SaveFileDialog()){saveFileDialog.Filter = "CSV文件 (*.csv)|*.csv|文本文件 (*.txt)|*.txt";saveFileDialog.Title = "保存結果";saveFileDialog.FileName = "OCR識別結果_" + DateTime.Now.ToString("yyyyMMddHHmmss");if (saveFileDialog.ShowDialog() == DialogResult.OK){try{StringBuilder csvContent = new StringBuilder();csvContent.AppendLine("序號,原始文件名,新文件名,識別內容,處理狀態");foreach (var item in renameItems){string ocrText = item.OcrText.Replace("\n", " ").Replace(",", ",");csvContent.AppendLine($"{item.Index},{item.OriginalFileName},{item.NewFileName},{ocrText},{item.Status}");}File.WriteAllText(saveFileDialog.FileName, csvContent.ToString(), Encoding.UTF8);MessageBox.Show("導出成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);}catch (Exception ex){MessageBox.Show($"導出失敗: {ex.Message}", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);}}}}// 輔助方法private void AddPdfFiles(string[] files){int addedCount = 0;foreach (string file in files){if (File.Exists(file) && Path.GetExtension(file).ToLower() == ".pdf"){if (!pdfFiles.Contains(file)){pdfFiles.Add(file);addedCount++;}}}if (addedCount > 0){txtSelectedFiles.Text = $"{pdfFiles.Count}個PDF文件";UpdatePreviewGrid();}}private void UpdatePreviewGrid(){dgvPreview.DataSource = null;dgvPreview.DataSource = renameItems;}private async Task ProcessPdfFilesAsync(){for (int i = 0; i < pdfFiles.Count; i++){string filePath = pdfFiles[i];string fileName = Path.GetFileName(filePath);lblProgress.Text = $"正在處理: {fileName} ({i+1}/{pdfFiles.Count})";progressBar.Value = i + 1;RenameItem item = new RenameItem{Index = i + 1,FilePath = filePath,OriginalFileName = fileName};try{// 從PDF中提取圖片List<byte[]> imageBytesList = ExtractImagesFromPdf(filePath);if (imageBytesList.Count == 0){item.Status = "失敗";item.ErrorMessage = "未從PDF中提取到圖片";renameItems.Add(item);continue;}// 對每張圖片進行OCR識別StringBuilder ocrTextBuilder = new StringBuilder();foreach (var imageBytes in imageBytesList){string ocrText = await PerformOcrAsync(imageBytes);ocrTextBuilder.AppendLine(ocrText);}item.OcrText = ocrTextBuilder.ToString();// 生成新文件名item.NewFileName = GenerateNewFileName(fileName, item.OcrText, i + 1);item.Status = "成功";}catch (Exception ex){item.Status = "失敗";item.ErrorMessage = ex.Message;}renameItems.Add(item);// 更新UIif (dgvPreview.InvokeRequired){dgvPreview.Invoke(new Action(UpdatePreviewGrid));}}}private List<byte[]> ExtractImagesFromPdf(string pdfPath){// 使用iTextSharp庫從PDF中提取圖片識別// 注意:需要添加iTextSharp引用List<byte[]> imageBytesList = new List<byte[]>();try{using (var reader = new iTextSharp.text.pdf.PdfReader(pdfPath)){for (int i = 1; i <= reader.NumberOfPages; i++){var resources = reader.GetPageResources(i);var names = resources.GetResourceNames(iTextSharp.text.pdf.PdfName.XOBJECT);if (names != null){foreach (var name in names){var obj = resources.GetResource(iTextSharp.text.pdf.PdfName.XOBJECT, name);if (obj is iTextSharp.text.pdf.PdfImageObject){var image = (iTextSharp.text.pdf.PdfImageObject)obj;var imageBytes = image.GetImageAsBytes();imageBytesList.Add(imageBytes);}}}}}}catch (Exception ex){throw new Exception($"提取PDF圖片失敗: {ex.Message}");}return imageBytesList;}private async Task<string> PerformOcrAsync(byte[] imageBytes){try{// 創建RestClientvar client = new RestClient(serviceEndpoint);// 根據選擇的OCR模板確定API路徑string apiPath = "/ocr/general"; // 默認為通用文字識別switch (cboOcrTemplate.SelectedIndex){case 0: // 通用文字識別apiPath = "/ocr/general";break;case 1: // 身份證識別apiPath = "/ocr/idcard";break;case 2: // 營業執照識別apiPath = "/ocr/businessLicense";break;case 3: // 增值稅發票識別apiPath = "/ocr/invoice";break;}var request = new RestRequest(apiPath, Method.Post);// 添加認證信息request.AddHeader("Content-Type", "application/json");request.AddHeader("x-jdcloud-access-key", accessKeyId);request.AddHeader("x-jdcloud-signature", GenerateSignature(apiPath, "POST"));// 準備請求體var requestBody = new{image = Convert.ToBase64String(imageBytes)};request.AddJsonBody(requestBody);// 執行請求var response = await client.ExecuteAsync(request);if (!response.IsSuccessful){throw new Exception($"OCR請求失敗: {response.StatusCode} - {response.Content}");}// 解析OCR結果dynamic result = JsonConvert.DeserializeObject(response.Content);// 根據不同的OCR模板解析結果string ocrText = "";if (cboOcrTemplate.SelectedIndex == 0) // 通用文字識別{if (result.code == 0 && result.data != null && result.data.wordsResult != null){foreach (var item in result.data.wordsResult){ocrText += item.words + "\n";}}}else // 其他特定模板識別{if (result.code == 0 && result.data != null){// 不同模板返回的數據結構不同,需要根據實際情況解析ocrText = JsonConvert.SerializeObject(result.data, Formatting.Indented);}}return ocrText.Trim();}catch (Exception ex){throw new Exception($"OCR識別失敗: {ex.Message}");}}private string GenerateSignature(string path, string method){// 注意:這里需要實現京東云的簽名算法// 具體實現可以參考京東云官方文檔:https://docs.jdcloud.com/cn/common-request-signature// 為簡化示例,這里返回一個占位符return "YOUR_GENERATED_SIGNATURE";}private string GenerateNewFileName(string originalFileName, string ocrText, int index){try{string format = txtNameFormat.Text.Trim();if (string.IsNullOrEmpty(format)){format = "{日期}_{關鍵詞}_{序號}";}string extension = Path.GetExtension(originalFileName);string fileNameWithoutExt = Path.GetFileNameWithoutExtension(originalFileName);// 提取日期string date = DateTime.Now.ToString("yyyyMMdd");// 提取時間string time = DateTime.Now.ToString("HHmmss");// 提取關鍵詞(從OCR文本中提取前20個字符)string keywords = ocrText.Length > 20 ? ocrText.Substring(0, 20) : ocrText;keywords = Regex.Replace(keywords, @"[^\w\s]", ""); // 移除非法字符keywords = keywords.Replace(" ", "_"); // 替換空格// 構建新文件名string newFileName = format.Replace("{日期}", date).Replace("{時間}", time).Replace("{關鍵詞}", keywords).Replace("{頁碼}", index.ToString()).Replace("{序號}", index.ToString("D3")).Replace("{原文件名}", fileNameWithoutExt);// 確保文件名不包含非法字符foreach (char c in Path.GetInvalidFileNameChars()){newFileName = newFileName.Replace(c, '_');}// 添加文件擴展名return newFileName + extension;}catch (Exception){// 如果生成失敗,使用默認格式return $"OCR_{DateTime.Now:yyyyMMddHHmmss}_{index:D3}{Path.GetExtension(originalFileName)}";}}private void LoadSettings(){try{if (File.Exists("settings.ini")){string[] lines = File.ReadAllLines("settings.ini");foreach (string line in lines){if (string.IsNullOrEmpty(line) || !line.Contains("=")){continue;}string[] parts = line.Split('=');if (parts.Length != 2){continue;}string key = parts[0].Trim();string value = parts[1].Trim();switch (key){case "AccessKey":accessKeyId = value;txtAccessKey.Text = value;break;case "SecretKey":secretAccessKey = value;txtSecretKey.Text = value;break;case "NameFormat":txtNameFormat.Text = value;break;case "Overwrite":chkOverwrite.Checked = value.ToLower() == "true";break;}}}}catch (Exception){// 忽略加載設置時的錯誤}}private void SaveSettings(){try{StringBuilder settings = new StringBuilder();settings.AppendLine($"AccessKey={accessKeyId}");settings.AppendLine($"SecretKey={secretAccessKey}");settings.AppendLine($"NameFormat={txtNameFormat.Text}");settings.AppendLine($"Overwrite={chkOverwrite.Checked}");File.WriteAllText("settings.ini", settings.ToString(), Encoding.UTF8);}catch (Exception){// 忽略保存設置時的錯誤}}}public class RenameItem{public int Index { get; set; }public string FilePath { get; set; }public string OriginalFileName { get; set; }public string OcrText { get; set; }public string NewFileName { get; set; }public string Status { get; set; }public string ErrorMessage { get; set; }}
}    

上述代碼實現了一個完整的 PDF 圖片識別改名工具,主要包含以下功能模塊:

  1. 界面設計與交互

    • 創建了文件選擇、OCR 配置、預覽和操作按鈕四個主要區域
    • 支持拖放和文件選擇對話框選擇 PDF 文件
    • 使用 DataGridView 展示處理結果和預覽
  2. PDF 圖片提取

    • 使用 iTextSharp 庫從 PDF 文件中提取圖片
    • 支持處理包含多張圖片的 PDF 文件
  3. 京東云 OCR 集成

    • 實現了與京東云 OCR API 的通信
    • 支持多種 OCR 模板(通用文字、身份證、營業執照、發票等)
    • 處理 API 返回結果并提取識別文本
  4. 文件名生成規則

    • 支持自定義命名格式,包含多種變量
    • 自動處理非法文件名字符
    • 提供靈活的命名規則配置
  5. 文件重命名功能

    • 支持批量重命名操作
    • 提供覆蓋選項和錯誤處理
    • 顯示詳細的處理結果和狀態
  6. 設置保存與加載

    • 保存和加載用戶配置
    • 提供配置持久化功能
四、總結與優化建議
  1. 性能優化

    • 對于大量 PDF 文件的處理,可以考慮使用多線程并行處理
    • 添加進度保存功能,支持斷點續傳
  2. 功能增強

    • 增加 OCR 識別結果編輯功能,允許用戶手動修正識別錯誤
    • 添加更多 OCR 模板支持,如表格識別、車牌識別等
    • 支持更復雜的命名規則,如正則表達式匹配
  3. 用戶體驗優化

    • 添加識別結果預覽和編輯功能
    • 增加操作日志記錄,方便追蹤問題
    • 支持導出詳細的處理報告
  4. 安全與穩定性

    • 改進異常處理機制,增強程序穩定性
    • 添加配置加密功能,保護敏感信息
    • 增加文件備份選項,防止誤操作

這個工具可以大大提高文檔處理效率,特別是對于需要大量 PDF 文件命名和分類的場景。根據實際需求,你可以進一步定制和擴展這個解決方案。

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

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

相關文章

stm32-modbus-rs485程序移植過程

背景 【modbus學習筆記】Modbus協議解析_modus協議中0.001如何解析-CSDN博客 【Modbus學習筆記】stm32實現Modbus(從機)并移植_stm32 modbus數據處理-CSDN博客 繼上篇成功移植modbus從機例程之后&#xff0c;我要嘗試移植主機的程序。經提醒&#xff0c;可用野火的modbus代碼…

Spring MVC 執行流程詳解:一次請求經歷了什么?

Spring MVC 執行流程詳解&#xff1a;一次請求經歷了什么&#xff1f; 引言 在現代 Web 開發中&#xff0c;Spring MVC 作為 Spring 框架的重要組成部分&#xff0c;廣泛應用于構建靈活、可擴展的 Java Web 應用。作為一個基于 MVC&#xff08;Model-View-Controller&#xff0…

Vue 3的核心機制-解析事件流、DOM更新、數據請求、DOM操作規范及組件庫DOM操作的解決方案

文章目錄概要整體介紹vue 中dom操作推薦方案實例概要 從Vue 3的核心機制出發&#xff0c;結合場景、應用與實例&#xff0c;系統化解析事件流、DOM更新、數據請求、DOM操作規范及組件庫DOM操作的解決方案&#xff1a; 整體介紹 ?? 一、事件流處理機制 核心機制 ? 三個階段…

Python從入門到高手9.2節-Python字典的操作方法

目錄 9.2.1 字典的操作 9.2.2 字典的查找 9.2.3 字典的修改 9.2.4 字典的添加 9.2.5 字典的刪除 9.2.6 今天你逛街了嗎 9.2.1 字典的操作 字典類型是一種抽象數據類型&#xff0c;抽象數據類型定義了數據類型的操作方法&#xff0c;在本節的內容中&#xff0c;教同學們徹…

omniparser v2 本地部署及制作docker鏡像(20250715)

關于 omniparser v2 本地部署&#xff0c;網上資料不算多&#xff0c;尤其是對于土薔內用戶&#xff0c;還是有些坑的。 1、安裝步驟 可參考兩個CSDN博客&#xff1a; &#xff08;1&#xff09;大模型實戰 - ‘OmniParser-V2本地部署安裝 鏈接 &#xff08;2&#xff09;…

自己寫個 `rsync` + `fswatch` 實時增量同步腳本,干掉 Cursor AI、Sublime Text 的SFTP等 插件!

自己寫個 rsync fswatch 實時增量同步腳本&#xff0c;干掉 Cursor AI、Sublime Text 的 SFTP等 插件&#xff01; 作為一個碼農&#xff0c;我最頭疼的事情之一就是編輯器同步代碼到服務器這塊。用過各種各樣的sftp、rsync插件&#xff0c;感覺不好用。。 我琢磨著&#xff1…

linux中at命令的常用用法。

Linux 中 at 命令用于安排一次性定時任務&#xff0c;需要用到在某個時間只需要執行一次的命令的時候&#xff0c;可以使用at 1&#xff1a;安裝at # Debian/Ubuntu sudo apt install at# CentOS/RHEL sudo yum install at2&#xff1a;啟動at sudo systemctl start atd # 啟…

【安卓筆記】RxJava的使用+修改功能+搭配retrofit+RxView防快速點擊

0. 環境&#xff1a; 電腦&#xff1a;Windows10 Android Studio: 2024.3.2 編程語言: Java Gradle version&#xff1a;8.11.1 Compile Sdk Version&#xff1a;35 Java 版本&#xff1a;Java11 1. 介紹RxJava GitHub開源地址&#xff1a;https://github.com/Reactive…

Windows 下原生使用 claude code + Kimi K2

搞定了kimi k2 claude code在windows下原生使用 Windows下使用claude code的障礙是shell環境&#xff08;命令行&#xff09;&#xff0c;非posix風格shell無法正常讓claude code讀取到url和key, 導致無法使用。解決問題的本質是使用符合posix風格的shell環境&#xff0c;我們…

Leetcode Easy題小解(C++語言描述)1

Leetcode Easy題小解&#xff08;C語言描述&#xff09; 相交鏈表 給你兩個單鏈表的頭節點 headA 和 headB &#xff0c;請你找出并返回兩個單鏈表相交的起始節點。如果兩個鏈表不存在相交節點&#xff0c;返回 null 。 圖示兩個鏈表在節點 c1 開始相交**&#xff1a;**題目數據…

EP01:【NLP 第二彈】自然語言處理概述

一、NLP通向智能之路 1.1 圖靈測試 1.1.1 提出背景 由計算機科學家阿蘭?圖靈于 1950 年提出&#xff0c;是早期衡量機器智能水平的重要概念。 1.1.2 提出目的 判斷機器是否能表現出與人類相當的智能行為。 1.1.3 測試原理 場景設定&#xff1a;測試中存在一位人類測試者&#…

Ansible 查看PostgreSQL的版本

Ansible的基礎知識就不說了直接貼劇本- name: Check PostgreSQL versionhosts: db_serversbecome: yesvars:ansible_python_interpreter: /usr/bin/python3db_name: postgresdb_user: postgresdb_password: your_passwordtasks:- name: Install psycopg2ansible.builtin.packag…

【視覺SLAM筆記】第9章 后端1

一、理論1. 狀態估計的概率解釋我們來深入探討一下視覺SLAM中狀態估計的概率解釋。這可以說是理解現代SLAM算法&#xff08;尤其是后端優化&#xff09;的基石1. 問題的核心&#xff1a;不確定性SLAM&#xff08;同步定位與建圖&#xff09;的本質是在一個未知環境中&#xff0…

(數據結構)復雜度

基本概念說明 數據結構 定義&#xff1a;數據結構(Data Structure)是計算機存儲、組織數據的方式&#xff0c;指相互之間存在?種或多種特定關系的數據元素的集合。沒有?種單?的數據結構對所有用途都有用&#xff08;要考慮適配、效率問題&#xff0c;在不同情況下使用合適的…

玩轉Docker | 使用Docker部署bender個人導航頁工具

玩轉Docker | 使用Docker部署bender個人導航頁工具 前言 一、bender介紹 Bender 簡介 Bender 的主要特點 二、系統要求 環境要求 環境檢查 Docker版本檢查 檢查操作系統版本 三、部署bender服務 下載bender鏡像 編輯部署文件 創建容器 檢查容器狀態 檢查服務端口 安全設置 四、…

解決了困擾我的upload靶場無法解析phtml等后綴的問題

本文章為解決困擾我的 upload 靶場無法解析 phtml 問題 ? 這個問題直接讓我過不了Upload-Pass-03這一關&#xff0c;一直卡著。 ? 痛太痛了 &#xff0c;為什么無法解析上傳之后的 phtml 后綴文件&#xff01;這塊兒折磨了博主一天多&#xff0c;太不容易了&#xff0c;查找…

Leetcode百題斬-二分搜索

二分搜索也是一個很有趣的專題&#xff0c;被做過的題中&#xff0c;剛好一個Easy&#xff0c;一個Medium和一個Hard&#xff0c;剛好可以看看&#xff0c;二分搜索的三個難度等級都是啥樣的。 124. Binary Tree Maximum Path Sum[Hard]&#xff08;詳見二叉樹專題&#xff09;…

【IDEA】格式化代碼工具配置

格式化代碼快捷鍵&#xff1a; CtrlAltL格式代碼的時候不會再方法名與參數中間添加空格默認不勾選的情況下&#xff1a;代碼樣例&#xff1a;勾選之后的樣例&#xff1a;選擇不勾選&#xff0c;IDEA默認情況下就是不勾選的狀態忽略加載文件有些非必要加載到開發工具中的文件我們…

驅動開發(3)|rk356x驅動GPIO基礎應用之點亮led燈

點亮LED燈看似是一個基礎的操作&#xff0c;但實際上&#xff0c;許多高級應用也依賴于高低電平的切換。例如&#xff0c;脈沖寬度調制&#xff08;PWM&#xff09;信號可以用來精確控制電機的轉速&#xff0c;通過改變脈沖的頻率和占空比&#xff0c;實現對電機的精確調節&…

手動搭建PHP環境:步步為營,解鎖Web開發

目錄一、引言二、準備工作2.1 明確所需軟件2.2 下載軟件三、Windows 系統搭建步驟3.1 安裝 Apache 服務器3.2 安裝 PHP3.3 集成 Apache 與 PHP3.4 安裝 MySQL3.5 配置 PHP 連接 MySQL四、Linux 系統搭建步驟&#xff08;以 Ubuntu 為例&#xff09;4.1 更新系統4.2 安裝 Apache…