【图片识别Excel】批量提取图片中的文字,图片设置识别区域,识别后将文字提取并保存Excel表格,基于WPF和OCR识别的应用
应用场景
在办公自动化、文档处理、数据录入等场景中,经常需要从大量图片中提取文字信息。例如:
- 批量处理扫描的表单、合同、发票等文档
- 从图片集中提取特定区域的文字数据
- 将纸质资料快速转换为电子文本并整理归档
通过设置识别区域,可以精准定位需要提取的内容,提高识别准确率,减少干扰信息。
界面设计
应用界面采用 WPF 实现,主要包含以下部分:
- 顶部导航栏:包含应用标题和功能按钮(选择图片、开始识别、保存结果)
- 左侧图片预览区:显示当前选中的图片及识别区域框
- 中间参数设置区:可调整识别区域坐标和大小
- 右侧结果预览区:展示识别出的文字内容
- 底部状态栏:显示处理进度和状态信息
详细代码步骤
下面是基于 WPF 和 Tesseract OCR 的实现代码:
using System.Windows;namespace OCRTextExtractor
{public partial class App : Application{protected override void OnStartup(StartupEventArgs e){base.OnStartup(e);// 确保Tesseract数据目录存在if (!System.IO.Directory.Exists("./tessdata")){System.IO.Directory.CreateDirectory("./tessdata");MessageBox.Show("请将Tesseract OCR语言数据文件(.traineddata)放到应用程序目录下的tessdata文件夹中。", "缺少OCR数据", MessageBoxButton.OK, MessageBoxImage.Warning);}}}
}
<Window x:Class="OCRTextExtractor.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="图片文字识别提取工具" Height="700" Width="1000"WindowStartupLocation="CenterScreen"><Grid><!-- 顶部导航栏 --><DockPanel Height="50" DockPanel.Dock="Top" Background="#333333"><Button Content="选择图片" Margin="10,5" Width="80" Command="{Binding SelectImagesCommand}" DockPanel.Dock="Left"/><Button Content="开始识别" Margin="10,5" Width="80" Command="{Binding StartRecognitionCommand}" DockPanel.Dock="Left"/><Button Content="保存结果" Margin="10,5" Width="80" Command="{Binding SaveResultsCommand}" DockPanel.Dock="Left"/><Label Content="{Binding StatusMessage}" Foreground="White" VerticalContentAlignment="Center" Margin="10,0"/></DockPanel><!-- 主体内容区 --><Grid><!-- 左侧图片预览区 --><GridSplitter Width="5" HorizontalAlignment="Left" Grid.Column="1" Background="#CCCCCC"/><Grid Grid.Column="0" Margin="10"><Label Content="图片预览" FontWeight="Bold" Margin="0,0,0,5"/><Border BorderBrush="Gray" BorderThickness="1" Margin="0,25,0,0"><Canvas x:Name="ImageCanvas" Background="LightGray" MouseLeftButtonDown="Canvas_MouseLeftButtonDown" MouseMove="Canvas_MouseMove" MouseLeftButtonUp="Canvas_MouseLeftButtonUp"><Image x:Name="PreviewImage" Stretch="Uniform"/><Rectangle x:Name="SelectionRect" Stroke="Red" StrokeThickness="2" Visibility="Hidden"/></Canvas></Border><StackPanel Orientation="Horizontal" Margin="0,5,0,0"><Button Content="上一张" Width="70" Command="{Binding PreviousImageCommand}" Margin="0,0,5,0"/><Button Content="下一张" Width="70" Command="{Binding NextImageCommand}"/><Label Content="{Binding CurrentImageInfo}" VerticalContentAlignment="Center" Margin="10,0,0,0"/></StackPanel></Grid><!-- 中间参数设置区 --><GridSplitter Width="5" HorizontalAlignment="Left" Grid.Column="3" Background="#CCCCCC"/><Grid Grid.Column="2" Margin="10"><Label Content="识别区域设置" FontWeight="Bold" Margin="0,0,0,5"/><StackPanel Orientation="Vertical" Margin="0,25,0,0"><GroupBox Header="区域坐标" Margin="0,0,0,10"><Grid Margin="5"><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Height="Auto"/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="Auto"/><ColumnDefinition Width="*"/><ColumnDefinition Width="Auto"/><ColumnDefinition Width="*"/></Grid.ColumnDefinitions><Label Content="X:" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center"/><TextBox Text="{Binding RecognitionRegion.X, Mode=TwoWay}" Grid.Row="0" Grid.Column="1" Margin="5,0"/><Label Content="Y:" Grid.Row="0" Grid.Column="2" VerticalAlignment="Center"/><TextBox Text="{Binding RecognitionRegion.Y, Mode=TwoWay}" Grid.Row="0" Grid.Column="3" Margin="5,0"/><Label Content="宽度:" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center"/><TextBox Text="{Binding RecognitionRegion.Width, Mode=TwoWay}" Grid.Row="1" Grid.Column="1" Margin="5,0"/><Label Content="高度:" Grid.Row="1" Grid.Column="2" VerticalAlignment="Center"/><TextBox Text="{Binding RecognitionRegion.Height, Mode=TwoWay}" Grid.Row="1" Grid.Column="3" Margin="5,0"/></Grid></GroupBox><GroupBox Header="OCR设置" Margin="0,0,0,10"><Grid Margin="5"><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Height="Auto"/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="Auto"/><ColumnDefinition Width="*"/></Grid.ColumnDefinitions><Label Content="识别语言:" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center"/><ComboBox ItemsSource="{Binding AvailableLanguages}" SelectedItem="{Binding SelectedLanguage}" Grid.Row="0" Grid.Column="1" Margin="5,0"/><CheckBox Content="自动保存每张识别结果" IsChecked="{Binding AutoSaveEachResult}" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="5,0"/></Grid></GroupBox><Button Content="应用设置" Command="{Binding ApplySettingsCommand}" Height="30"/></StackPanel></Grid><!-- 右侧结果预览区 --><Grid Grid.Column="4" Margin="10"><Label Content="识别结果" FontWeight="Bold" Margin="0,0,0,5"/><Border BorderBrush="Gray" BorderThickness="1" Margin="0,25,0,0"><TextBox Text="{Binding RecognizedText, Mode=TwoWay}" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" IsReadOnly="True"/></Border><StackPanel Orientation="Horizontal" Margin="0,5,0,0"><Label Content="处理进度:" VerticalContentAlignment="Center"/><ProgressBar Value="{Binding ProgressValue}" Maximum="{Binding ProgressMaximum}" Width="200" Margin="5,0"/><Label Content="{Binding ProgressText}" VerticalContentAlignment="Center" Margin="5,0"/></StackPanel></Grid></Grid></Grid>
</Window>
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.Win32;
using Prism.Commands;
using Prism.Mvvm;
using Tesseract;namespace OCRTextExtractor
{public partial class MainWindow : Window{public MainWindow(){InitializeComponent();DataContext = new MainViewModel();}private Point? startPoint = null;private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e){startPoint = e.GetPosition(ImageCanvas);SelectionRect.Visibility = Visibility.Visible;ImageCanvas.CaptureMouse();}private void Canvas_MouseMove(object sender, MouseEventArgs e){if (startPoint.HasValue && e.LeftButton == MouseButtonState.Pressed){var endPoint = e.GetPosition(ImageCanvas);double x = Math.Min(startPoint.Value.X, endPoint.X);double y = Math.Min(startPoint.Value.Y, endPoint.Y);double width = Math.Abs(endPoint.X - startPoint.Value.X);double height = Math.Abs(endPoint.Y - startPoint.Value.Y);SelectionRect.SetValue(Canvas.LeftProperty, x);SelectionRect.SetValue(Canvas.TopProperty, y);SelectionRect.Width = width;SelectionRect.Height = height;var viewModel = DataContext as MainViewModel;if (viewModel != null){viewModel.RecognitionRegion.X = x;viewModel.RecognitionRegion.Y = y;viewModel.RecognitionRegion.Width = width;viewModel.RecognitionRegion.Height = height;}}}private void Canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e){startPoint = null;ImageCanvas.ReleaseMouseCapture();}}public class MainViewModel : BindableBase{private List<string> imageFiles = new List<string>();private int currentImageIndex = 0;private BitmapSource currentImage;private string recognizedText;private string statusMessage = "就绪";private Rect recognitionRegion = new Rect(100, 100, 300, 200);private double progressValue;private double progressMaximum;private string progressText = "0/0";private bool autoSaveEachResult = false;private string selectedLanguage = "chi_sim";private List<string> availableLanguages = new List<string> { "eng", "chi_sim", "jpn" };public BitmapSource CurrentImage{get { return currentImage; }set { SetProperty(ref currentImage, value); }}public string RecognizedText{get { return recognizedText; }set { SetProperty(ref recognizedText, value); }}public string StatusMessage{get { return statusMessage; }set { SetProperty(ref statusMessage, value); }}public Rect RecognitionRegion{get { return recognitionRegion; }set { SetProperty(ref recognitionRegion, value); }}public double ProgressValue{get { return progressValue; }set { SetProperty(ref progressValue, value); }}public double ProgressMaximum{get { return progressMaximum; }set { SetProperty(ref progressMaximum, value); }}public string ProgressText{get { return progressText; }set { SetProperty(ref progressText, value); }}public bool AutoSaveEachResult{get { return autoSaveEachResult; }set { SetProperty(ref autoSaveEachResult, value); }}public string SelectedLanguage{get { return selectedLanguage; }set { SetProperty(ref selectedLanguage, value); }}public List<string> AvailableLanguages{get { return availableLanguages; }set { SetProperty(ref availableLanguages, value); }}public string CurrentImageInfo{get{if (imageFiles.Count == 0)return "未选择图片";return $"图片 {currentImageIndex + 1}/{imageFiles.Count}: {Path.GetFileName(imageFiles[currentImageIndex])}";}}public ICommand SelectImagesCommand { get; private set; }public ICommand PreviousImageCommand { get; private set; }public ICommand NextImageCommand { get; private set; }public ICommand StartRecognitionCommand { get; private set; }public ICommand SaveResultsCommand { get; private set; }public ICommand ApplySettingsCommand { get; private set; }public MainViewModel(){SelectImagesCommand = new DelegateCommand(SelectImages);PreviousImageCommand = new DelegateCommand(PreviousImage, CanNavigateImage).ObservesProperty(() => CurrentImageInfo);NextImageCommand = new DelegateCommand(NextImage, CanNavigateImage).ObservesProperty(() => CurrentImageInfo);StartRecognitionCommand = new DelegateCommand(StartRecognition, CanStartRecognition).ObservesProperty(() => CurrentImageInfo);SaveResultsCommand = new DelegateCommand(SaveResults, CanSaveResults).ObservesProperty(() => RecognizedText);ApplySettingsCommand = new DelegateCommand(ApplySettings);}private void SelectImages(){var openFileDialog = new OpenFileDialog{Filter = "图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif|所有文件|*.*",Multiselect = true,Title = "选择图片文件"};if (openFileDialog.ShowDialog() == true){imageFiles = openFileDialog.FileNames.ToList();currentImageIndex = 0;LoadCurrentImage();StatusMessage = $"已选择 {imageFiles.Count} 张图片";}}private void LoadCurrentImage(){if (imageFiles.Count > 0){try{var image = new BitmapImage(new Uri(imageFiles[currentImageIndex]));CurrentImage = image;RecognizedText = "";RaisePropertyChanged(nameof(CurrentImageInfo));}catch (Exception ex){StatusMessage = $"加载图片时出错: {ex.Message}";}}}private bool CanNavigateImage(){return imageFiles.Count > 0;}private void PreviousImage(){if (currentImageIndex > 0){currentImageIndex--;LoadCurrentImage();}}private void NextImage(){if (currentImageIndex < imageFiles.Count - 1){currentImageIndex++;LoadCurrentImage();}}private bool CanStartRecognition(){return imageFiles.Count > 0;}private void StartRecognition(){try{StatusMessage = "开始识别...";ProgressMaximum = imageFiles.Count;ProgressValue = 0;var results = new List<(string FileName, string Text)>();foreach (var imageFile in imageFiles){var text = RecognizeTextFromImage(imageFile);results.Add((Path.GetFileName(imageFile), text));if (AutoSaveEachResult){SaveSingleResult(imageFile, text);}ProgressValue++;ProgressText = $"{ProgressValue}/{ProgressMaximum}";}// 合并所有识别结果RecognizedText = string.Join(Environment.NewLine + "------------------------" + Environment.NewLine, results.Select(r => $"文件名: {r.FileName}{Environment.NewLine}识别结果:{Environment.NewLine}{r.Text}"));StatusMessage = "识别完成";}catch (Exception ex){StatusMessage = $"识别过程中出错: {ex.Message}";}}private string RecognizeTextFromImage(string imagePath){try{using (var engine = new TesseractEngine(@"./tessdata", SelectedLanguage, EngineMode.Default)){using (var img = Pix.LoadFromFile(imagePath)){// 截取识别区域if (RecognitionRegion.Width > 0 && RecognitionRegion.Height > 0){int x = (int)Math.Max(0, RecognitionRegion.X);int y = (int)Math.Max(0, RecognitionRegion.Y);int width = (int)Math.Min(img.Width - x, RecognitionRegion.Width);int height = (int)Math.Min(img.Height - y, RecognitionRegion.Height);if (width > 0 && height > 0){using (var region = img.Copy(x, y, width, height)){using (var page = engine.Process(region)){return page.GetText();}}}}// 如果区域无效,则处理全图using (var page = engine.Process(img)){return page.GetText();}}}}catch (Exception ex){StatusMessage = $"处理图片 {Path.GetFileName(imagePath)} 时出错: {ex.Message}";return $"[识别出错: {ex.Message}]";}}private void SaveSingleResult(string imagePath, string text){try{string resultPath = Path.ChangeExtension(imagePath, ".txt");File.WriteAllText(resultPath, text);}catch { } // 忽略单个文件保存错误}private bool CanSaveResults(){return !string.IsNullOrEmpty(RecognizedText);}private void SaveResults(){var saveFileDialog = new SaveFileDialog{Filter = "文本文件|*.txt|Excel文件|*.xlsx|所有文件|*.*",Title = "保存识别结果",DefaultExt = "txt"};if (saveFileDialog.ShowDialog() == true){try{if (Path.GetExtension(saveFileDialog.FileName).ToLower() == ".xlsx"){SaveToExcel(saveFileDialog.FileName);}else{File.WriteAllText(saveFileDialog.FileName, RecognizedText);}StatusMessage = $"结果已保存到 {saveFileDialog.FileName}";}catch (Exception ex){StatusMessage = $"保存结果时出错: {ex.Message}";}}}private void SaveToExcel(string filePath){// 使用EPPlus库创建Excel文件using (var package = new OfficeOpenXml.ExcelPackage(new FileInfo(filePath))){var worksheet = package.Workbook.Worksheets.Add("识别结果");// 分割多个图片的识别结果var results = RecognizedText.Split(new[] { "------------------------" }, StringSplitOptions.RemoveEmptyEntries);// 添加标题行worksheet.Cells[1, 1].Value = "图片文件名";worksheet.Cells[1, 2].Value = "识别文本";// 填充数据for (int i = 0; i < results.Length; i++){var lines = results[i].Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);if (lines.Length >= 2 && lines[0].StartsWith("文件名:")){string fileName = lines[0].Substring(5).Trim();string text = string.Join(Environment.NewLine, lines.Skip(1));worksheet.Cells[i + 2, 1].Value = fileName;worksheet.Cells[i + 2, 2].Value = text;}}// 自动调整列宽worksheet.Cells.AutoFitColumns();// 保存文件package.Save();}}private void ApplySettings(){StatusMessage = "已应用识别区域设置";}}
}
总结优化
这个应用实现了从图片中批量提取文字并保存到 Excel 的功能,主要特点包括:
- 用户友好的界面:直观的图片预览和识别区域设置功能
- 灵活的识别区域调整:支持鼠标绘制和手动输入坐标两种方式
- 多语言支持:内置多种语言识别选项
- 批量处理能力:支持多张图片连续处理
- 结果导出:支持将识别结果保存为文本或 Excel 格式
优化建议
-
性能优化:
- 可以添加多线程处理,提高批量识别效率
- 实现识别结果的缓存机制,避免重复处理
-
功能增强:
- 添加图片预处理功能(灰度化、二值化、降噪等)提高识别准确率
- 支持识别结果的编辑和校对
- 增加更多导出格式选项(如 CSV、PDF 等)
-
用户体验:
- 添加识别进度的详细信息和预估时间
- 支持保存和加载识别区域配置
- 提供快捷键支持,提高操作效率
使用时,需要在应用程序目录下创建tessdata
文件夹,并放入相应的语言数据文件(.traineddata),可以从 Tesseract GitHub 仓库下载。
相关文章:

【图片识别Excel】批量提取图片中的文字,图片设置识别区域,识别后将文字提取并保存Excel表格,基于WPF和OCR识别的应用
应用场景 在办公自动化、文档处理、数据录入等场景中,经常需要从大量图片中提取文字信息。例如: 批量处理扫描的表单、合同、发票等文档从图片集中提取特定区域的文字数据将纸质资料快速转换为电子文本并整理归档 通过设置识别区域,可以精…...
深入理解 Java 多线程:原理剖析与实战指南
深入理解 Java 多线程:原理剖析与实战指南 一、引言 在现代软件开发中,多线程编程已经成为提升应用性能与响应能力的重要手段。Java 作为一门成熟的编程语言,自 JDK 1.0 起就提供了对多线程的原生支持。本文将深入剖析 Java 多线程的底层原…...

Qt/C++学习系列之Excel使用记录
Qt/C学习系列之Excel使用记录 前言The process was ended forcefully.解决方式断点查语句问题 总结 前言 在项目中解析条目达50多条,并且都需要将对应的结果进行显示。为了将结果显示的更加清晰,考虑采用QTableWidget进行表格设置,而在使用过…...

跳转指令四维全解:从【call/jmp 】的时空法则到内存迷宫导航术
一、核心概念:代码世界的空间定位法则 在汇编世界里,我们可以把内存想象成一栋巨大的图书馆: CS(代码段寄存器) 楼层编号 IP(指令指针) 房间编号 当前执行位置 CS:IP(如3楼201…...

LabVIEW实时系统数据监控与本地存储
基于LabVIEW Real-Time 模块,面向工业自动化、嵌入式测控等场景,提供实时数据采集、监控与本地存储的完整实现路径。通过分层任务调度、TDMS 文件格式应用及跨平台兼容性设计,确保系统在实时性、可靠性与数据管理效率间达到平衡。文中以 Comp…...

从 Revit 到 3DTiles:GISBox RVT 切片器如何让建筑图元在 Web 端展示
在GIS(地理信息系统)行业蓬勃发展的当下,数据处理与展示的效率和精准度成为关键。GISBox作为一款功能强大的一站式三维GIS数据编辑、转换、发布平台,凭借其独特的“RVT切片器”功能,在RVT图元处理方面也有着不俗的表现…...

Appium+python自动化(十二)- Android UIAutomator
Android团队在4.1版本(API 16)中推出了一款全新的UI自动化测试工具UiAutomator,用来帮助开发人员更有效率的完成App的Debug工作,同时对于测试人员也是一大福音,为什么这么说呢? UiAutomator提供了以下两种…...
在C语言中使用UUID作为AES加密密钥
在C语言中使用UUID作为AES加密密钥 编译依赖安装示例代码编译和运行关键点说明注意事项编译依赖安装 运行环境位centos8 Linux 4.18.0-348.7.1.el8_5.x86_64 #1 SMP Wed Dec …...
Nginx+Tomcat负载均衡集群
目录 一、Tomcat 基础与单节点部署 (一)Tomcat 概述 (二)单节点部署案例 1. 案例环境 2. 实施准备 3. 安装 JDK 4. 查看 JDK 安装情况 5. 安装配置 Tomcat 6. 启动 Tomcat 7. 访问测试 8. 关闭 Tomcat (三…...

QQ邮箱发送验证码(Springboot)
一、邮箱发送服务准备 在qq邮箱的设置中选择账号下开启服务。 开启时可能会有短信验证,开启后显示验证码之类的一串英文,复制保存起来,在配置文件中会使用到。 二、后端依赖及配置 依赖 在pom.yml文件中添加相关依赖,redis的…...
Python Copilot【代码辅助工具】 简介
粉丝爱买鳕鱼肠深海鳕鱼肉鱼肉香肠盼盼麦香鸡味块卡乐比(Calbee)薯条三兄弟 独立小包美丽雅 奶茶杯一次性饮料杯好时kisses多口味巧克力糖老金磨方【黑金系列】黑芝麻丸郑新初网红郑新初烤鲜牛肉干超人毛球修剪器去球器剃毛器衣服去毛器优惠券宁之春 红黑…...
如何写高效的Prompt?
概述 提示词(Prompt)的质量将直接影响模型生成结果的质量,所以精心设计一个让大模型能够理解并有效回复的提示词是至关重要的。本文内容自论文中获取:https://arxiv.org/pdf/2312.16171 介绍了5类共计26条提示词书写原则。 书写原则 类别原则备注快速…...

【EF Core】 EF Core并发控制:乐观锁与悲观锁的应用
文章目录 前言一、并发的风险二、EF Core中的并发控制方式2.1 开放式并发(乐观锁)2.1.1 应用程序管理的属性并发令牌2.1.2 数据库生成的并发令牌 2.2 悲观锁 总结 前言 实际的生产环境中,我们经常能遇到数据库由多个应用程序同时使用。每个程…...
WaytoAGI东京大会开启AI全球化新对话:技术无国界,合作促创新
全球AI专家齐聚东京,一场关于技术无国界的对话正在进行。 2025年6月7日,一场备受瞩目的AI盛会——“WaytoAGI全球AI大会东京站”在日本东京樱美林大学新宿校区正式拉开帷幕。这场为期两天的会议(6月7日至8日)由国内最大的AI开源知…...

Harmony核心:动态方法修补与.NET游戏Mod开发
一、Harmony的核心定位与设计哲学 Harmony是一个运行时动态方法修补库,专为修改已编译的.NET/Mono应用程序而设计,尤其适用于游戏Mod开发。其核心创新在于: 非破坏性修改:保留原始方法完整性,避免直接替换或覆盖。多…...
AI系统应用开发工程师
以下是对AI系统应用开发与运维岗位的梳理整合,从企业、岗位、任务、能力等维度进行分类呈现,便于清晰对比两者的工作侧重: 一、代表性企业对比 分类企业名称应用开发方向中移系统集成有限公司、科大讯飞河北科技有限公司、华为技术服务有限…...
Qt Test功能及架构
Qt Test 是 Qt 框架中的单元测试模块,在 Qt 6.0 中提供了全面的测试功能。 一、主要功能 核心功能 1. 单元测试框架 提供完整的单元测试基础设施 支持测试用例、测试套件的组织和执行 包含断言宏和测试结果收集 2. 测试类型支持 单元测试:对单个函…...
图像处理、图像分析和图像理解的定义、联系与区别
1. 定义 图像处理(Image Processing) 图像处理是低层操作,主要针对像素级的图像数据进行加工,目的是改善图像质量或为后续分析做准备。 典型任务:去噪、增强(如对比度调整)、锐化、边缘检测、图…...

【Java开发日记】说一说 SpringBoot 中 CommandLineRunner
目录 1、CommandLineRunner SpringBoot中CommandLineRunner的作用 简单例子 多个类实现CommandLineRunner接口执行顺序的保证 通过实现Ordered接口实现控制执行顺序 通过Order注解实现控制执行顺序 Order 作用 2、ApplicationRunner 3、传递参数 4、源码跟踪 run()方…...

全面理解 Linux 内核性能问题:分类、实战与调优策略
在 Linux 系统(特别是嵌入式或服务器环境)中,性能问题往往错综复杂、表象多变。只有对常见性能问题进行系统归类、理解其症状与根源,才能有效定位和解决。本文将围绕八大类核心性能问题,结合实战示例,逐类分…...

算法-多条件排序
1、数对排序的使用 pair<ll,ll> a[31];//cmp为比较规则 ll cmp(pair<ll,ll>a,pair<ll,ll>b){if(a.first!b.first)return a.first>b.first;else return a.second<b.second; }//按照比较规则进行排序 sort(a1,a31,cmp); 2、具体例题 输入样例࿱…...
DelayQueue、ScheduledThreadPoolExecutor 和 PriorityBlockingQueue :怎么利用堆实现定时任务
DelayQueue DelayQueue 的最大亮点: 并不是简单全局锁的“单调队列”实现,而是用Leader-Follower 模式极大减少了线程唤醒的开销。插入与唤醒、等待与 leader 变更,都通过巧妙的锁和条件变量组合完成。 如果只关注“线程安全的优先队列全局…...
Kafka 消息模式实战:从简单队列到流处理(二)
四、Kafka 流处理实战 4.1 Kafka Streams 简介 Kafka Streams 是 Kafka 提供的流处理库,它为开发者提供了一套简洁而强大的 API,用于构建实时流处理应用程序。Kafka Streams 基于 Kafka 的高吞吐量、分布式和容错特性,能够处理大规模的实时…...
大数据(2) 大数据处理架构Hadoop
一、Hadoop简介 1.定义 Hadoop 是一个开源的分布式计算框架,由 Apache 基金会开发,用于处理海量数据,具备高可靠性、高扩展性和高容错性。它主要由两个核心模块组成: HDFS(Hadoop Distributed File System)…...
【Kotlin】注解反射扩展
文章目录 注解用法反射类引用 扩展扩展函数的作用域成员方法优先级总高于扩展函数 被滥用的扩展函数扩展属性静态扩展 标准库中的扩展函数 使用 T.also 函数交换两个变量sNullOrEmpty | isNullOrBlankwith函数repeat函数 调度方式对扩展函数的影响静态与动态调度扩展函数始终静…...

固定ip和非固定ip的区别是什么?如何固定ip地址
在互联网中,我们常会接触到固定IP和非固定IP的概念。它们究竟有何不同?如何固定IP地址?让我们一起来探究这个问题。 一、固定IP和非固定IP的区别是什么 固定IP(静态IP)和非固定IP(动态IP)是两种…...
升级centos 7.9内核到 5.4.x
前面是指南,后面是工作日志。 wget http://mirrors.coreix.net/elrepo-archive-archive/kernel/el7/x86_64/RPMS/kernel-lt-devel-5.4.225-1.el7.elrepo.x86_64.rpm wget http://mirrors.coreix.net/elrepo-archive-archive/kernel/el7/x86_64/RPMS/kernel-lt-5.4.2…...
Nginx 安全设置配置
1、增加header公共文件 文件地址:/etc/nginx/conf.d/security_headers.conf # XSS防护配置add_header X-XSS-Protection "1; modeblock" always; # 其他安全配置add_header X-Content-Type-Options "nosniff";add_header X-Frame-Options &qu…...
协程的常用阻塞函数
以下是一些常见的阻塞函数示例: 1. **Thread.sleep()** 阻塞当前线程一段时间。 kotlin Thread.sleep(1000) // 阻塞线程 1 秒 2. **InputStream.read()** 从输入流中读取数据时会阻塞,直到有数据可用或流结束。 kotlin val inputStream FileInputStre…...
探索NoSQL注入的奥秘:如何消除MongoDB查询中的前置与后置条件
随着互联网技术的飞速发展,数据库作为信息存储与管理的核心,其安全性问题日益凸显。近年来,NoSQL数据库因其灵活性和高性能逐渐成为许多企业的首选,其中MongoDB以其文档存储和JSON-like查询语言在开发社区中广受欢迎。然而&#x…...