diff --git a/TextLocator/App.xaml.cs b/TextLocator/App.xaml.cs index 345fbf2406974a636dfa8224ce957ac393114a3c..7fc2692b272861b693458875c6c43ff24e531d1e 100644 --- a/TextLocator/App.xaml.cs +++ b/TextLocator/App.xaml.cs @@ -1,15 +1,14 @@ using log4net; using System; -using System.Collections.Generic; -using System.Configuration; -using System.Data; -using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; using System.Windows; +using TextLocator.Core; using TextLocator.Enums; using TextLocator.Factory; using TextLocator.Service; +using TextLocator.Util; namespace TextLocator { @@ -21,9 +20,38 @@ namespace TextLocator private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); public App() + { + // 初始化线程池大小 + InitThreadPoolSize(); + + // 初始化文件信息服务引擎 + InitFileInfoServiceEngine(); + } + + /// + /// 初始化线程池大小 + /// + private void InitThreadPoolSize() + { + bool setMinThread = ThreadPool.SetMinThreads(AppConst.THREAD_POOL_MIN_SIZE, AppConst.THREAD_POOL_MIN_SIZE); + log.Debug("修改线程池最小线程数量:" + AppConst.THREAD_POOL_MIN_SIZE + " => " + setMinThread); + bool setMaxThread = ThreadPool.SetMaxThreads(AppConst.THREAD_POOL_MAX_SIZE, AppConst.THREAD_POOL_MAX_SIZE); + log.Debug("修改线程池最大线程数量:" + AppConst.THREAD_POOL_MAX_SIZE + " => " + setMaxThread); + + // 保存线程池 + AppUtil.WriteValue("ThreadPool", "MinSize", AppConst.THREAD_POOL_MIN_SIZE + ""); + AppUtil.WriteValue("ThreadPool", "MaxSize", AppConst.THREAD_POOL_MAX_SIZE + ""); + } + + + /// + /// 初始化文件信息服务引擎 + /// + private void InitFileInfoServiceEngine() { try { + log.Debug("初始化文件引擎工厂"); // Word服务 FileInfoServiceFactory.Register(FileType.Word文档, new WordFileService()); // Excel服务 diff --git a/TextLocator/Core/AppConst.cs b/TextLocator/Core/AppConst.cs index 3f7704289f36ae0b0c65f8500fa394e9e19052a3..03ed748216174c70d823829d47b53480279635d0 100644 --- a/TextLocator/Core/AppConst.cs +++ b/TextLocator/Core/AppConst.cs @@ -1,7 +1,9 @@ using JiebaNet.Segmenter; using System; using System.IO; +using System.Text.RegularExpressions; using TextLocator.Jieba; +using TextLocator.Util; namespace TextLocator.Core { @@ -10,6 +12,14 @@ namespace TextLocator.Core /// public class AppConst { + /// + /// 线程池最小数量 + /// + public static readonly int THREAD_POOL_MIN_SIZE = int.Parse(AppUtil.ReadValue("ThreadPool", "MinSize", "4")); + /// + /// 线程池最大数量 + /// + public static readonly int THREAD_POOL_MAX_SIZE = int.Parse(AppUtil.ReadValue("ThreadPool", "MaxSize", "8")); /// /// 应用目录 /// @@ -19,6 +29,10 @@ namespace TextLocator.Core /// public static readonly string APP_INDEX_DIR = Path.Combine(APP_DIR, "Index"); /// + /// App.ini路径:_AppDir\\_AppName\\Index_Build\\ + /// + public static readonly string APP_INDEX_BUILD_DIR = Path.Combine(APP_DIR, "Index_Build"); + /// /// 分词器 /// new Lucene.Net.Analysis.Cn.ChineseAnalyzer(); /// new Lucene.Net.Analysis.Standard.StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30);// 用standardAnalyzer分词器 @@ -35,5 +49,33 @@ namespace TextLocator.Core /// 内存:new Lucene.Net.Store.RAMDirectory() /// public static readonly Lucene.Net.Store.FSDirectory INDEX_DIRECTORY = Lucene.Net.Store.FSDirectory.Open(new DirectoryInfo(APP_INDEX_DIR)); + /// + /// 索引写入初始化(FSDirectory表示索引存放在硬盘上,RAMDirectory表示放在内存上) + /// 磁盘路径:Lucene.Net.Store.FSDirectory.Open(new DirectoryInfo(_AppIndexDir)) + /// 内存:new Lucene.Net.Store.RAMDirectory() + /// + public static readonly Lucene.Net.Store.FSDirectory INDEX_BUILD_DIRECTORY = Lucene.Net.Store.FSDirectory.Open(new DirectoryInfo(APP_INDEX_BUILD_DIR)); + + /// + /// 搜索最大值限制 + /// + public static readonly int MAX_COUNT_LIMIT = int.Parse(AppUtil.ReadValue("AppConfig", "MaxCountLimit", "100")); + + /// + /// 匹配特殊字符 + /// + public static readonly Regex REGIX_SPECIAL_CHARACTER = new Regex("`|~|!|@|#|\\$|%|\\^|&|\\*|\\(|\\)|_|\\-|\\+|\\=|\\[|\\]|\\{|\\}|\\\\|\\||;|:|'|\"|,|\\<|\\.|\\>|\\/|\\?|"); + /// + /// 匹配空白和换行 + /// + public static readonly Regex REGIX_LINE_BREAKS_AND_WHITESPACE = new Regex(" |\r|\n|\\s"); + /// + /// 匹配HTML和XML标签 + /// + public static readonly Regex REGIX_TAG = new Regex("\\<.[^<>]*\\>"); + /// + /// 匹配文件后缀 + /// + public static readonly Regex REGIX_FILE_EXT = new Regex(@"^.+\.(" + FileTypeUtil.GetFileTypeExts("|") + ")$"); } } diff --git a/TextLocator/Core/TaskTime.cs b/TextLocator/Core/TaskTime.cs new file mode 100644 index 0000000000000000000000000000000000000000..63aec50886f9c11ca1b4f6dc9c47cf4dc14a525b --- /dev/null +++ b/TextLocator/Core/TaskTime.cs @@ -0,0 +1,44 @@ +using System; + +namespace TextLocator.Core +{ + /// + /// 任务时间 + /// + public class TaskTime + { + /// + /// 开始时间 + /// + private DateTime beginTime; + + /// + /// 构造函数 + /// + public TaskTime() + { + beginTime = DateTime.Now; + } + + /// + /// 消耗时间 + /// + /// + public double ConsumeTime + { + get + { + return (DateTime.Now - beginTime).TotalSeconds; + } + } + + /// + /// 开始新任务 + /// + /// + public static TaskTime StartNew() + { + return new TaskTime(); ; + } + } +} diff --git a/TextLocator/Factory/FileInfoServiceFactory.cs b/TextLocator/Factory/FileInfoServiceFactory.cs index 078df1e83daaddd41b6310d4e6e5e788ebd479a1..e9227dd18bdb382c56f52bf96be54b6ae259fef3 100644 --- a/TextLocator/Factory/FileInfoServiceFactory.cs +++ b/TextLocator/Factory/FileInfoServiceFactory.cs @@ -43,6 +43,7 @@ namespace TextLocator.Factory /// 服务实例 public static void Register(FileType fileType, IFileInfoService fileInfoService) { + log.Debug((int)fileType + ":" + fileType.ToString() + " 引擎注册"); services.Add(fileType, fileInfoService); } } diff --git a/TextLocator/FileInfoItem.xaml.cs b/TextLocator/FileInfoItem.xaml.cs index 9511625260f632d772532069c9ce48fe0764a239..02e75aafc3334ee062e957a4f40310ff9e782d4e 100644 --- a/TextLocator/FileInfoItem.xaml.cs +++ b/TextLocator/FileInfoItem.xaml.cs @@ -1,8 +1,6 @@ using log4net; using System; -using System.Windows; using System.Windows.Controls; -using System.Windows.Documents; using System.Windows.Media; using TextLocator.Util; @@ -54,12 +52,11 @@ namespace TextLocator string fileName = fileInfo.FileName; // 显示文件名称 - RichTextBoxUtil.FillingData(this.FileName, fileName.Length > 90 ? fileName.Substring(0, 90) : fileName, (Brush)new BrushConverter().ConvertFromString("#1A0DAB"), true); + RichTextBoxUtil.FillingData(this.FileName, fileName.Length > 55 ? fileName.Substring(0, 55) + "..." : fileName, (Brush)new BrushConverter().ConvertFromString("#1A0DAB"), true); string filePath = fileInfo.FilePath.Replace(fileInfo.FileName, ""); - this.FileFolder.ToolTip = filePath; // 文件路径 - RichTextBoxUtil.FillingData(this.FileFolder, filePath.Length > 100 ? filePath.Substring(0, 100) + "..." : filePath, (Brush)new BrushConverter().ConvertFromString("#006621")); + RichTextBoxUtil.FillingData(this.FileFolder, filePath.Length > 70 ? filePath.Substring(0, 70) + "..." : filePath, (Brush)new BrushConverter().ConvertFromString("#006621")); // 结果列表内容预览 RichTextBoxUtil.FillingData(this.FileContent, fileInfo.Breviary, (Brush)new BrushConverter().ConvertFromString("#545454")); diff --git a/TextLocator/FolderWindow.xaml.cs b/TextLocator/FolderWindow.xaml.cs index ad5a3e99b0fd437f0b6100af2da4cc3585e98fce..2c773a661c0c61502ab58a37f66eef2d845d4c3c 100644 --- a/TextLocator/FolderWindow.xaml.cs +++ b/TextLocator/FolderWindow.xaml.cs @@ -19,15 +19,15 @@ namespace TextLocator private void Window_Loaded(object sender, RoutedEventArgs e) { // 获取已有搜索去 - string folderPaths = AppUtil.ReadIni("AppConfig", "FolderPaths", Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "," + Environment.GetFolderPath(Environment.SpecialFolder.Desktop)); + string folderPaths = AppUtil.ReadValue("AppConfig", "FolderPaths", Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "," + Environment.GetFolderPath(Environment.SpecialFolder.Desktop)); if (!string.IsNullOrEmpty(folderPaths)) { // 清空 this.FolderList.Items.Clear(); - + FolderInfoItem folder; foreach (string folderPath in folderPaths.Split(',')) { - FolderInfoItem folder = new FolderInfoItem(folderPath); + folder = new FolderInfoItem(folderPath); folder.DeleteButton.Click += DeleteButton_Click; folder.DeleteButton.Tag = folderPath; @@ -93,7 +93,7 @@ namespace TextLocator folderPaths = folderPaths.Substring(0, folderPaths.Length - 1); // 保存到配置文件 - AppUtil.WriteIni("AppConfig", "FolderPaths", folderPaths); + AppUtil.WriteValue("AppConfig", "FolderPaths", folderPaths); this.DialogResult = true; diff --git a/TextLocator/Index/IndexCore.cs b/TextLocator/Index/IndexCore.cs index 0641316c956b0801978a638752887138bf4b2332..89c30625fe3283c0fc15978226a57c12807bbc83 100644 --- a/TextLocator/Index/IndexCore.cs +++ b/TextLocator/Index/IndexCore.cs @@ -46,51 +46,64 @@ namespace TextLocator.Index public static void CreateIndex(List filePaths, bool rebuild, Callback callback) { // 判断是创建索引还是增量索引(如果索引目录不存在,重建) - bool create = !Directory.Exists(AppConst.APP_INDEX_DIR); + bool create = !Directory.Exists(AppConst.APP_INDEX_BUILD_DIR); // 入参为true,表示重建 if (rebuild) { create = rebuild; - } + } + + // 重建或创建 + if (create) + { + // 重建时,删除全部已建索引的标记 + AppUtil.DeleteSection("FileIndex"); + } // 索引写入初始化(FSDirectory表示索引存放在硬盘上,RAMDirectory表示放在内存上) Lucene.Net.Index.IndexWriter indexWriter = new Lucene.Net.Index.IndexWriter( - AppConst.INDEX_DIRECTORY, + AppConst.INDEX_BUILD_DIRECTORY, AppConst.INDEX_ANALYZER, create, Lucene.Net.Index.IndexWriter.MaxFieldLength.UNLIMITED); // 文件总数 - int count = filePaths.Count(); + int totalCount = filePaths.Count(); // 每次初始化的时候完成数量都是0 finishCount = 0; - using (var countDown = new MutipleThreadResetEvent(count)) + using (MutipleThreadResetEvent resetEvent = new MutipleThreadResetEvent(totalCount)) { // 遍历读取文件,并创建索引 - for (int i = 0; i < count; i++) + for (int i = 0; i < totalCount; i++) { + string filePath = filePaths[i]; + // 忽略已存在索引的文件 + if (SkipFile(create, filePath, totalCount, callback, resetEvent)) + { + continue; + } // 加入线程池 ThreadPool.QueueUserWorkItem(new WaitCallback(CreateIndexTask), new TaskInfo() { - TotalCount = count, + TotalCount = totalCount, FilePath = filePaths[i], - Create = create, IndexWriter = indexWriter, Callback = callback, - ResetEvent = countDown + ResetEvent = resetEvent }); } // 等待所有线程结束 - countDown.WaitAll(); + resetEvent.WaitAll(); // 销毁 - countDown.Dispose(); + resetEvent.Dispose(); } try { + // 索引写入器销毁 indexWriter.Dispose(); } catch (Exception ex) @@ -99,6 +112,44 @@ namespace TextLocator.Index } } + /// + /// 忽略文件 + /// + /// 是否是创建,true为创建、false为更新 + /// 文件路径 + /// 文件总数 + /// 状态回调函数 + /// 多线程任务标记 + private static bool SkipFile(bool create, string filePath, int totalCount, Callback callback, MutipleThreadResetEvent resetEvent) + { + // 非重建 && 文件已经被索引过 + bool isUpdate = !create; + bool isExists = !string.IsNullOrEmpty(AppUtil.ReadValue("FileIndex", filePath, "")); + if (isUpdate && isExists) + { + string skipMsg = "跳过文件:" + filePath; + + callback(skipMsg, CalcCompletionRatio(finishCount, totalCount)); + + lock (locker) + { + finishCount++; + } + + try + { + resetEvent.SetOne(); + } + catch { } + +#if !DEBUG + log.Debug(skipMsg); +#endif + return true; + } + return false; + } + /// /// 创建索引任务方法 /// @@ -107,30 +158,16 @@ namespace TextLocator.Index { TaskInfo taskInfo = obj as TaskInfo; try - { - string filePath = taskInfo.FilePath; + { Lucene.Net.Index.IndexWriter indexWriter = taskInfo.IndexWriter; - // 临时文件跳过 - if (filePath.IndexOf("~$") > 0) - { - return; - } - // 非重建 && 文件已经被索引过 - bool isUpdate = !taskInfo.Create; - bool isExists = !string.IsNullOrEmpty(AppUtil.ReadIni("FileIndex", filePath, "")); - if (isUpdate && isExists) - { -#if DEBUG - log.Debug("非重建,索引存在 => 跳过:" + filePath); -#endif - return; - } + string filePath = taskInfo.FilePath; + // 写入 - AppUtil.WriteIni("FileIndex", filePath, "1"); + AppUtil.WriteValue("FileIndex", filePath, "1"); // 开始时间 - DateTime beginMark = DateTime.Now; + var taskMark = TaskTime.StartNew(); // 文件信息 FileInfo fileInfo = new FileInfo(filePath); @@ -139,9 +176,7 @@ namespace TextLocator.Index // 文件大小 long fileSize = fileInfo.Length; // 创建时间 - string createTime = fileInfo.CreationTime.ToString("yyyy-MM-dd"); - // 文件标记 - string fileMark = fileInfo.DirectoryName + fileInfo.CreationTime.ToString(); + string createTime = fileInfo.CreationTime.ToString("yyyy-MM-dd"); // 根据文件路径获取文件类型(自定义文件类型分类) FileType fileType = FileTypeUtil.GetFileType(filePath); @@ -150,12 +185,15 @@ namespace TextLocator.Index string content = FileInfoServiceFactory.GetFileInfoService(fileType).GetFileContent(filePath); // 缩略信息 - string breviary = new Regex(" |\r|\n|\\s").Replace(content, ""); + string breviary = AppConst.REGIX_LINE_BREAKS_AND_WHITESPACE.Replace(content, ""); if (breviary.Length > 150) { breviary = breviary.Substring(0, 150) + "..."; } + // 文件标记 + string fileMark = MD5Util.GetMD5Hash(filePath); //fileInfo.DirectoryName + fileInfo.CreationTime.ToString(); + lock (locker) { // 当索引文件中含有与filemark相等的field值时,会先删除再添加,以防出现重复 @@ -179,10 +217,10 @@ namespace TextLocator.Index indexWriter.Optimize(); } - string msg = "索引:[" + finishCount * 1.0F + "/" + taskInfo.TotalCount + "] => 文件:" + filePath + ",耗时:" + (DateTime.Now - beginMark).TotalSeconds + "秒"; + string msg = "解析文件:[" + finishCount * 1.0F + "/" + taskInfo.TotalCount + "] => 引擎:" + (int)fileType + ",文件:" + filePath + ",耗时:" + taskMark.ConsumeTime + "秒"; // 执行状态回调 - taskInfo.Callback(msg, finishCount * 1.00F / taskInfo.TotalCount * 1.00F * 100.00F); + taskInfo.Callback(msg, CalcCompletionRatio(finishCount, taskInfo.TotalCount)); log.Debug(msg); } @@ -192,33 +230,58 @@ namespace TextLocator.Index } finally { - lock (locker) { finishCount++; } - // 手动GC - GC.Collect(); - GC.WaitForPendingFinalizers(); - try { taskInfo.ResetEvent.SetOne(); - } catch { } + } + catch { } + + // 手动GC + GC.Collect(); + GC.WaitForPendingFinalizers(); } } + /// + /// 计算完成比例 + /// + /// + /// + /// + private static double CalcCompletionRatio(double finishCount, double totalCount) + { + return finishCount * 1.00F / totalCount * 1.00F * 100.00F; + } + /// /// 任务信息 /// class TaskInfo { + /// + /// 文件总数 + /// public int TotalCount { get; set; } + /// + /// 文件路径 + /// public string FilePath { get; set; } - public bool Create { get; set; } + /// + /// 索引写入器 + /// public Lucene.Net.Index.IndexWriter IndexWriter { get; set; } - public IndexCore.Callback Callback { get; set; } + /// + /// 回调函数 + /// + public Callback Callback { get; set; } + /// + /// 多线程重置 + /// public MutipleThreadResetEvent ResetEvent { get; set; } } } diff --git a/TextLocator/MainWindow.xaml b/TextLocator/MainWindow.xaml index 54a11eb2c446413f698297fe5d8b0b39e1e3890b..57b0bb2951a668a6c4b9487c78f67fe47440848d 100644 --- a/TextLocator/MainWindow.xaml +++ b/TextLocator/MainWindow.xaml @@ -20,7 +20,7 @@ - + @@ -112,7 +112,7 @@ - + @@ -144,17 +144,18 @@ - + + - + - 教 师 护 导 要 求(20210219).doc + 配置信息详细报告.doc @@ -166,13 +167,19 @@ - + - 项目1、乙方为甲方网站的服务器进行维护和管理,包括:病毒排查和清除、网站数据的备份,网站空间的定期清理和维护,服务器帐号的管理等服务,保证网站的正常运行和网站数据的完整性以及网站服务器帐号的安全。 项目2、乙方为甲方网站的系统程序进行维护和管理,包括:程序代码的整理和优化、排除程序代码的漏洞、排除因系统错误导致的故障、保证网站系统的正常运行。... + --------[ 概览 ]---------------------------------------------------------------------------------- + 电脑型号 X64 兼容 台式电脑 + 操作系统 Windows 10 专业版 64位 ( Version 2004 / DirectX 12 ) + 处理器 AMD Ryzen 9 3900X 12-Core + 主板 华硕 PRIME X570-P ( AMD PCI 标准主机 CPU 桥 ) + 显卡 Nvidia GeForce RTX 2080 Ti ( 11 GB / 七彩虹 ) + 内存 64 GB ( 海盗船 DDR4 3200MHz )... @@ -185,7 +192,7 @@ - + @@ -201,9 +208,9 @@ - + - + @@ -216,23 +223,548 @@ - 网站维护合同书 -甲方名称:尚迪(上海)铝业有限公司 乙方名称: -联系电话:021-37595166 联系电话: - -甲、乙双方在平等自愿的基础上,经友好协商,就甲方委托乙方进行网站运行护及网 -站信息维护的有关事宜达成一致,签订本合同。合同主要服务内容如下: - -第一条:双方的权利和义务 -一、乙方的权利和义务 -(1)乙方为甲方的网站https://www.sdfaal.com/ _提供如下网站维护的服务 - -项目1、乙方为甲方网站的服务器进行维护和管理,包括:病毒排查和清除、网站数据的备份,网站空间的定期清理和维护,服务器帐号的管理等服务,保证网站的正常运行和网站数据的完整性以及网站服务器帐号的安全。 -项目2、乙方为甲方网站的系统程序进行维护和管理,包括:程序代码的整理和优化、排除程序代码的漏洞、排除因系统错误导致的故障、保证网站系统的正常运行。如甲方要求在当前网站系统的功能之上,重新增加新的网站系统或修改现有功能基础上之外的功能.需另外支付费用。 -项目3、乙方为甲方网站的信息内容进行维护和管理,包括:网站文字内容信息的修改(不包括网站FLASHI、网站版式以及网站风格的修改)、公司产品信息的数据备份。如 -甲方要求在当前网站风格、版式以及页面数的基础上,重新增加功能性新的页面或修 -改网站风格和版式时,需另外支付费用。 -顶目4、乙方为甲方网站的数据库进行维护和管理,包括:对网站数据库进行整理和优化、定期检测数据库的信息的准确性、清除多余数据、定期备份数据库等服务。保证网站数据库数据的合法、完整以及难确。 + +--------[ 概览 ]---------------------------------------------------------------------------------- + + 电脑型号 X64 兼容 台式电脑 + 操作系统 Windows 10 专业版 64位 ( Version 2004 / DirectX 12 ) + + 处理器 AMD Ryzen 9 3900X 12-Core + 主板 华硕 PRIME X570-P ( AMD PCI 标准主机 CPU 桥 ) + 显卡 Nvidia GeForce RTX 2080 Ti ( 11 GB / 七彩虹 ) + 内存 64 GB ( 海盗船 DDR4 3200MHz ) + 主硬盘 创见 TS256GMTE220S ( 256 GB / 固态硬盘 ) + 显示器 冠捷 AOC2790 U2790B ( 27.2 英寸 ) + 声卡 瑞昱 @ AMD High Definition Audio 控制器 + 网卡 瑞昱 RTL8168/8111/8112 Gigabit Ethernet Controller / 华硕 +--------[ 主板 ]---------------------------------------------------------------------------------- + + 主板型号 华硕 PRIME X570-P + 芯片组 AMD PCI 标准主机 CPU 桥 + 序列号 190652794505186 + 主板版本 Rev X.0x + BIOS American Megatrends Inc. 2204 / BIOS程序发布日期: 06/17/2020 + BIOS的大小 16384 KB + BIOS的序列号 IeiEr3Ul6IOzeS4EAT8EQeiGuD + + 板载设备 视频设备 (启用) + +--------[ 处理器 ]-------------------------------------------------------------------------------- + + 处理器 AMD Ryzen 9 3900X 12-Core + 速度 3.80 GHz (100 MHz x 38.0) + 处理器数量 核心数: 12 / 线程数: 24 + 插槽/插座 AM4 + 一级数据缓存 32 KB, 16-Way, 64 byte lines + 一级代码缓存 32 KB, 16-Way, 64 byte lines + 二级缓存 12 x 512 KB, 8-Way, 64 byte lines + 三级缓存 64 MB, 8-Way, 64 byte lines + 特征 MMX+, SSE, SSE2, SSE3, SSSE3, SSE4A, SSE4.1, HTT, X86-64 + +--------[ 硬盘 ]---------------------------------------------------------------------------------- + + 产品 西数 WDC WD10JPVX-22JC3T0 + 大小 1 TB + 转速 5400 转/分 + 缓存 8 MB + 硬盘已使用 共 1493 次,累计 10617 小时 + 固件 01.01A01 + 接口 SATA III + 数据传输率 600.00 MB/秒 + 特征 S.M.A.R.T, APM, 48-bit LBA, NCQ + + 产品 西数 WDC WD10JPVX-22JC3T0 + 大小 1 TB + 转速 5400 转/分 + 缓存 8 MB + 硬盘已使用 共 238 次,累计 594 小时 + 固件 01.01A01 + 接口 SATA III + 数据传输率 600.00 MB/秒 + 特征 S.M.A.R.T, APM, 48-bit LBA, NCQ + + 产品 希捷 ST2000DM008-2FR102 + 大小 2 TB + 转速 7200 转/分 + 缓存 256 MB + 硬盘已使用 共 430 次,累计 4274 小时 + 固件 0001 + 接口 SATA III + 数据传输率 600.00 MB/秒 + 特征 S.M.A.R.T, APM, 48-bit LBA, NCQ + + 产品 创见 TS256GMTE220S (固态硬盘) + 大小 256 GB + 硬盘已使用 共 286 次,累计 3809 小时 + 固件 S0328C + 接口 NVM Express + 特征 S.M.A.R.T + + 产品 Asgard AN2+ 256NVMe-M.2/80 (固态硬盘) + 大小 256 GB + 硬盘已使用 共 441 次,累计 4271 小时 + 固件 S0614B0G + 接口 NVM Express + 特征 S.M.A.R.T + +--------[ 内存 ]---------------------------------------------------------------------------------- + + DIMM_A1 海盗船 DDR4 3200MHz 16GB + 型号 7F7F9E CM4X16GC3200C16K2E + 厂商 Corsair + 模块位宽: 64 Bits + 模块电压: SSTL 1.2V + + DIMM_A2 海盗船 DDR4 3200MHz 16GB + 型号 7F7F9E CM4X16GC3200C16K2E + 厂商 Corsair + 模块位宽: 64 Bits + 模块电压: SSTL 1.2V + + DIMM_B1 海盗船 DDR4 3200MHz 16GB + 型号 7F7F9E CM4X16GC3200C16K2E + 厂商 Corsair + 模块位宽: 64 Bits + 模块电压: SSTL 1.2V + + DIMM_B2 海盗船 DDR4 3200MHz 16GB + 型号 7F7F9E CM4X16GC3200C16K2E + 厂商 Corsair + 模块位宽: 64 Bits + 模块电压: SSTL 1.2V + +--------[ 显卡 ]---------------------------------------------------------------------------------- + + 主显卡 Nvidia GeForce RTX 2080 Ti + 显存 11 GB + 制造商 七彩虹 + 制造商 Nvidia + 驱动版本 27.21.14.5148 + 驱动日期 20200621 + +--------[ 显示器 ]-------------------------------------------------------------------------------- + + 产品 冠捷 AOC2790 U2790B + 厂商 冠捷 + 固件程序日期 2019 年 38 周 (非显示器制造日期) + 屏幕尺寸 27.2 英寸 (60 厘米 x 34 厘米) + 显示比例 宽屏 16 : 9 + 分辨率 3840 x 2160 32 位真彩色 + Gamma 2.20 + 电源管理 Active-Off + +--------[ 其他设备 ]------------------------------------------------------------------------------ + + + 网卡 瑞昱 RTL8168/8111/8112 Gigabit Ethernet Controller + 制造商 华硕 + + 无线网卡 瑞昱 802.11n NIC + + 声卡 Nvidia GeForce 7800 GTX @ Nvidia High Definition Audio 控制器 + + 声卡 瑞昱 @ AMD High Definition Audio 控制器 + + 键盘 HID 标准键盘 + 键盘 HID 标准键盘 + 键盘 HID 标准键盘 + 鼠标 HID-compliant 鼠标 + + +--------[ PCI设备 ]------------------------------------------------------------------------------- + + 设备 PCI 标准主机 CPU 桥 + 设备ID 1480 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to HOST + 子系统制造商 ASUSTeK + 子系统ID 87C01043 + + 设备 IOMMU Device + 设备ID 1481 + 制造商 AMD + 制造商ID 1022 + 类别 System / + 子系统制造商 ASUSTeK + 子系统ID 87C01043 + + 设备 PCI 标准主机 CPU 桥 + 设备ID 1482 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to HOST + 子系统ID 00000000 + + 设备 PCI 到 PCI 桥 + 设备ID 1483 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to PCI + 子系统ID 00000000 + + 设备 PCI 到 PCI 桥 + 设备ID 1483 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to PCI + 子系统ID 00000000 + + 设备 PCI 标准主机 CPU 桥 + 设备ID 1482 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to HOST + 子系统ID 00000000 + + 设备 PCI 标准主机 CPU 桥 + 设备ID 1482 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to HOST + 子系统ID 00000000 + + 设备 PCI 到 PCI 桥 + 设备ID 1483 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to PCI + 子系统ID 00000000 + + 设备 PCI 标准主机 CPU 桥 + 设备ID 1482 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to HOST + 子系统ID 00000000 + + 设备 PCI 标准主机 CPU 桥 + 设备ID 1482 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to HOST + 子系统ID 00000000 + + 设备 PCI 标准主机 CPU 桥 + 设备ID 1482 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to HOST + 子系统ID 00000000 + + 设备 PCI 到 PCI 桥 + 设备ID 1484 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to PCI + 子系统ID 00000000 + + 设备 PCI 标准主机 CPU 桥 + 设备ID 1482 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to HOST + 子系统ID 00000000 + + 设备 PCI 到 PCI 桥 + 设备ID 1484 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to PCI + 子系统ID 00000000 + + 设备 SMBus + 设备ID 790B + 制造商 AMD + 制造商ID 1022 + 类别 Serial / SMBus Controller + 子系统制造商 ASUSTeK + 子系统ID 87C01043 + + 设备 PCI 标准 ISA 桥 + 设备ID 790E + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to ISA + 子系统制造商 ASUSTeK + 子系统ID 87C01043 + + 设备 PCI 标准主机 CPU 桥 + 设备ID 1440 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to HOST + 子系统ID 00000000 + + 设备 PCI 标准主机 CPU 桥 + 设备ID 1441 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to HOST + 子系统ID 00000000 + + 设备 PCI 标准主机 CPU 桥 + 设备ID 1442 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to HOST + 子系统ID 00000000 + + 设备 PCI 标准主机 CPU 桥 + 设备ID 1443 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to HOST + 子系统ID 00000000 + + 设备 PCI 标准主机 CPU 桥 + 设备ID 1444 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to HOST + 子系统ID 00000000 + + 设备 PCI 标准主机 CPU 桥 + 设备ID 1445 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to HOST + 子系统ID 00000000 + + 设备 PCI 标准主机 CPU 桥 + 设备ID 1446 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to HOST + 子系统ID 00000000 + + 设备 PCI 标准主机 CPU 桥 + 设备ID 1447 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to HOST + 子系统ID 00000000 + + 设备 标准 NVM Express 控制器 + 设备ID 2262 + 制造商 Silicon Motion + 制造商ID 126F + 类别 Storage / + 子系统制造商 Silicon Motion + 子系统ID 2262126F + + 设备 X570 Chipset + 设备ID 57AD + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to PCI + 子系统ID 00000000 + + 设备 PCI Express 下游交换机端口 + 设备ID 57A3 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to PCI + 子系统ID 00000000 + + 设备 PCI Express 下游交换机端口 + 设备ID 57A3 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to PCI + 子系统ID 00000000 + + 设备 PCI Express 下游交换机端口 + 设备ID 57A4 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to PCI + 子系统ID 00000000 + + 设备 PCI Express 下游交换机端口 + 设备ID 57A4 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to PCI + 子系统ID 00000000 + + 设备 PCI Express 下游交换机端口 + 设备ID 57A4 + 制造商 AMD + 制造商ID 1022 + 类别 Bridge / PCI to PCI + 子系统ID 00000000 + + 设备 标准 NVM Express 控制器 + 设备ID 2263 + 制造商 Silicon Motion + 制造商ID 126F + 类别 Storage / + 子系统制造商 Silicon Motion + 子系统ID 2263126F + + 设备 RTL8168/8111/8112 Gigabit Ethernet Controller + 设备ID 8168 + 制造商 Realtek + 制造商ID 10EC + 类别 Network / Ethernet + 子系统制造商 ASUSTeK + 子系统ID 86771043 + + 设备 PCI + 设备ID 1485 + 制造商 AMD + 制造商ID 1022 + 类别 / + 子系统制造商 ASUSTeK + 子系统ID 87C01043 + + 设备 符合 USB xHCI 的主机控制器 + 设备ID 149C + 制造商 AMD + 制造商ID 1022 + 类别 Serial / USB (UHCI) + 子系统制造商 ASUSTeK + 子系统ID 87C01043 + + 设备 符合 USB xHCI 的主机控制器 + 设备ID 149C + 制造商 AMD + 制造商ID 1022 + 类别 Serial / USB (UHCI) + 子系统制造商 AMD + 子系统ID 148C1022 + + 设备 标准 SATA AHCI 控制器 + 设备ID 7901 + 制造商 AMD + 制造商ID 1022 + 类别 Storage / Serial ATA (AHCI 1.0) + 子系统制造商 AMD + 子系统ID 79011022 + + 设备 标准 SATA AHCI 控制器 + 设备ID 7901 + 制造商 AMD + 制造商ID 1022 + 类别 Storage / Serial ATA (AHCI 1.0) + 子系统制造商 AMD + 子系统ID 79011022 + + 设备 GeForce RTX 2080 Ti + 设备ID 1E04 + 制造商 Nvidia + 制造商ID 10DE + 类别 Display / VGA + 子系统制造商 Colorful + 子系统ID 16507377 + + 设备 High Definition Audio 控制器 + 设备ID 10F7 + 制造商 Nvidia + 制造商ID 10DE + 类别 Multimedia / Hi-definition Audio + 子系统制造商 Colorful + 子系统ID 16507377 + + 设备 USB 3.10 可扩展主机控制器 - 1.10 (Microsoft) + 设备ID 1AD6 + 制造商 Nvidia + 制造商ID 10DE + 类别 Serial / USB (UHCI) + 子系统制造商 Colorful + 子系统ID 16507377 + + 设备 USB Type-C Port Policy Controller + 设备ID 1AD7 + 制造商 Nvidia + 制造商ID 10DE + 类别 Serial / Other + 子系统制造商 Colorful + 子系统ID 16507377 + + 设备 PCI + 设备ID 148A + 制造商 AMD + 制造商ID 1022 + 类别 / + 子系统制造商 ASUSTeK + 子系统ID 87C01043 + + 设备 PCI + 设备ID 1485 + 制造商 AMD + 制造商ID 1022 + 类别 / + 子系统制造商 ASUSTeK + 子系统ID 87C01043 + + 设备 PSP 11.0 Device + 设备ID 1486 + 制造商 AMD + 制造商ID 1022 + 类别 En/Decryption / Other + 子系统制造商 ASUSTeK + 子系统ID 87C01043 + + 设备 符合 USB xHCI 的主机控制器 + 设备ID 149C + 制造商 AMD + 制造商ID 1022 + 类别 Serial / USB (UHCI) + 子系统制造商 ASUSTeK + 子系统ID 87C01043 + + 设备 High Definition Audio 控制器 + 设备ID 1487 + 制造商 AMD + 制造商ID 1022 + 类别 Multimedia / Hi-definition Audio + 子系统制造商 ASUSTeK + 子系统ID 87BB1043 + +--------[ USB设备 ]------------------------------------------------------------------------------- + + 制造商ID 18F8 + 产品ID 1286 + 类别 0 / 0 / 0 + 设备 ? USB GAMING MOUSE + Serial ? + 版本 USB 1.1 + + 制造商ID 0BDA + 产品ID 8179 + 类别 0 / 0 / 0 + 设备 Realtek 802.11n NIC + Serial 00E04C0001 + 版本 USB 2.0 + + 制造商ID 0C45 + 产品ID 6510 + 类别 0 / 0 / 0 + 设备 SONiX USB DEVICE + Serial ? + 版本 USB 2.0 + + 制造商ID 0B05 + 产品ID 18F3 + 类别 0 / 0 / 0 + 设备 AsusTek Computer Inc. AURA LED Controller + Serial 9876543210 + 版本 USB 2.0 + +--------[ 传感器 ]-------------------------------------------------------------------------------- + + 名称 WINBOND NCT6798D + CPU温度 73℃ + CPU核心 74℃ + 主板 36℃ + 显卡 58℃ + 硬盘温度 42℃ + 风扇 1050转 + + + diff --git a/TextLocator/MainWindow.xaml.cs b/TextLocator/MainWindow.xaml.cs index 97143fc88933b0f1de7389649246655a78be9491..23f3a5b9684ef40fab5f5c0445e15de1922aeafa 100644 --- a/TextLocator/MainWindow.xaml.cs +++ b/TextLocator/MainWindow.xaml.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; @@ -26,7 +27,6 @@ namespace TextLocator { private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - /// /// 索引构建中 /// @@ -59,7 +59,25 @@ namespace TextLocator CleanSearchResult(); // 检查索引是否存在 - CheckIndexExist(); + if (CheckIndexExist()) + { + foreach(FileInfo fi in new DirectoryInfo(AppConst.APP_INDEX_DIR).GetFiles()) + { + using (StreamReader reader = new StreamReader(fi.FullName, Encoding.UTF8)) + { + reader.ReadToEnd(); + } + } + } + + // 检查配置参数信息 + if (string.IsNullOrEmpty(AppUtil.ReadValue("AppConfig", "MaxCountLimit", ""))) + { + AppUtil.WriteValue("AppConfig", "MaxCountLimit", AppConst.MAX_COUNT_LIMIT + ""); + } + + // 软件每次启动时执行索引更新逻辑? + } #region 初始化 @@ -69,28 +87,27 @@ namespace TextLocator private void InitializeFileTypeFilters() { // 文件类型筛选下拉框数据初始化 - this.FileTypeFilter.Items.Clear(); - this.FileTypeFilter.Items.Add("全部"); - this.FileTypeNames.Children.Clear(); + FileTypeFilter.Items.Clear(); + FileTypeFilter.Items.Add("全部"); + FileTypeNames.Children.Clear(); // 获取文件类型枚举,遍历并加入下拉列表 foreach (FileType fileType in Enum.GetValues(typeof(FileType))) { - this.FileTypeFilter.Items.Add(fileType.ToString()); + FileTypeFilter.Items.Add(fileType.ToString()); // 标签 - Button ft = new Button() + FileTypeNames.Children.Add(new Button() { Content = fileType.ToString(), Height = 25, - Margin = new Thickness(this.FileTypeNames.Children.Count == 0 ? 0 : 2, 0, 0, 0), + Margin = new Thickness(FileTypeNames.Children.Count == 0 ? 0 : 2, 0, 0, 0), ToolTip = fileType.GetDescription(), Background = Brushes.Gray - }; - this.FileTypeNames.Children.Add(ft); + }); } // 默认选中全部 - this.FileTypeFilter.SelectedIndex = 0; + FileTypeFilter.SelectedIndex = 0; } /// @@ -101,7 +118,7 @@ namespace TextLocator // 初始化显示被索引的文件夹列表 _IndexFolders.Clear(); // 读取被索引文件夹配置信息,如果配置信息为空:默认为我的文档和我的桌面 - string customFolders = AppUtil.ReadIni("AppConfig", "FolderPaths", Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "," + Environment.GetFolderPath(Environment.SpecialFolder.Desktop)); + string customFolders = AppUtil.ReadValue("AppConfig", "FolderPaths", Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "," + Environment.GetFolderPath(Environment.SpecialFolder.Desktop)); // 配置信息不为空 if (!string.IsNullOrEmpty(customFolders)) { @@ -116,8 +133,8 @@ namespace TextLocator { foldersText += folder + ", "; } - this.FolderPaths.Text = foldersText.Substring(0, foldersText.Length - 2); - this.FolderPaths.ToolTip = this.FolderPaths.Text; + FolderPaths.Text = foldersText.Substring(0, foldersText.Length - 2); + FolderPaths.ToolTip = FolderPaths.Text; } #endregion @@ -148,7 +165,8 @@ namespace TextLocator { Task.Factory.StartNew(() => { - DateTime beginMark = DateTime.Now; + var taskMark = TaskTime.StartNew(); + // 定义文件列表 List filePaths = new List(); foreach (string s in _IndexFolders) @@ -161,19 +179,25 @@ namespace TextLocator // 创建索引方法 IndexCore.CreateIndex(filePaths, rebuild, ShowStatus); - string msg = "索引执行结束,共用时:" + (DateTime.Now - beginMark).TotalSeconds + "秒"; + // 索引拷贝前删除 + FileUtil.RemoveDirectory(AppConst.APP_INDEX_DIR); + + // 索引拷贝:索引创建结束后拷贝新索引覆盖旧的索引,并删除write.lock + FileUtil.CopyDirectory(AppConst.APP_INDEX_BUILD_DIR, AppConst.APP_INDEX_DIR); + + string msg = "索引完成。共用时:" + taskMark.ConsumeTime + "秒"; // 显示状态 ShowStatus(msg); - this.Dispatcher.BeginInvoke(new Action(() => + Dispatcher.BeginInvoke(new Action(() => { Message.ShowSuccess("MessageContainer", msg); })); // 构建结束 build = false; - }); + }); } /// @@ -183,11 +207,11 @@ namespace TextLocator /// private void ShowStatus(string text, double percent = 100) { - this.Dispatcher.BeginInvoke(new Action(() => { - this.WorkStatus.Text = text; + Dispatcher.BeginInvoke(new Action(() => { + WorkStatus.Text = text; if (percent > 0) { - this.WorkProgress.Value = percent; + WorkProgress.Value = percent; } })); } @@ -201,24 +225,24 @@ namespace TextLocator /// 匹配全词 private void Search(List keywords, string fileType, bool onlyFileName = false, bool matchWords = false) { - ThreadPool.QueueUserWorkItem(_ => { - // 开始时间标记 - DateTime beginMark = DateTime.Now; + if (!CheckIndexExist()) + { + return; + } + Thread t = new Thread(() => { // 清空搜索结果列表 - this.Dispatcher.BeginInvoke(new Action(() => - { - this.SearchResultList.Items.Clear(); + Dispatcher.BeginInvoke(new Action(() => { + SearchResultList.Items.Clear(); })); - int num = 100; + + // 开始时间标记 + var taskMark = TaskTime.StartNew(); + Lucene.Net.Index.IndexReader reader = null; Lucene.Net.Search.IndexSearcher searcher = null; try { - if (!CheckIndexExist()) - { - return; - } reader = Lucene.Net.Index.IndexReader.Open(AppConst.INDEX_DIRECTORY, false); searcher = new Lucene.Net.Search.IndexSearcher(reader); @@ -276,16 +300,25 @@ namespace TextLocator Bquery.Add(new Lucene.Net.Search.TermQuery(new Lucene.Net.Index.Term("FileType", fileType)), Lucene.Net.Search.Occur.MUST); } - Lucene.Net.Search.TopScoreDocCollector collector = Lucene.Net.Search.TopScoreDocCollector.Create(num, true); + Lucene.Net.Search.TopScoreDocCollector collector = Lucene.Net.Search.TopScoreDocCollector.Create(AppConst.MAX_COUNT_LIMIT, true); searcher.Search(Bquery, collector); // 以后就可以对获取到的collector数据进行操作 var hits = collector.TopDocs().ScoreDocs; // 计算检索结果数量 int resultNum = 0; + + // 索引文档分数 + Lucene.Net.Search.ScoreDoc hit; + // 索引文档对象 + Lucene.Net.Documents.Document doc; + // 文件信息 + FileInfo fi; + // 显示文件信息 + Entity.FileInfo fileInfo; for (int i = 0; i < hits.Count(); i++) { - var hit = hits[i]; - Lucene.Net.Documents.Document doc = searcher.Doc(hit.Doc); + hit = hits[i]; + doc = searcher.Doc(hits[i].Doc); Lucene.Net.Documents.Field fileTypeField = doc.GetField("FileType"); Lucene.Net.Documents.Field fileNameField = doc.GetField("FileName"); Lucene.Net.Documents.Field filePathField = doc.GetField("FilePath"); @@ -305,55 +338,63 @@ namespace TextLocator continue; } - // 文件信息 - FileInfo fi = new FileInfo(filePathField.StringValue); - - log.Debug(fileNameField.StringValue + " => " + filePathField.StringValue + " , " + fileSizeField.StringValue + " , " + createTimeField.StringValue); - Entity.FileInfo fileInfo = new Entity.FileInfo() - { - FileType = (FileType)System.Enum.Parse(typeof(FileType), fileTypeField.StringValue), - - FileName = fileNameField.StringValue, - FilePath = filePathField.StringValue, - Breviary = breviaryField.StringValue, - - FileSize = long.Parse(fileSizeField.StringValue), - - CreateTime = createTimeField.StringValue, - Keywords = keywords - }; + // 文件信息 + fi = new FileInfo(filePathField.StringValue); - this.Dispatcher.BeginInvoke(new Action(() => + // 构造显示文件信息 + fileInfo = new Entity.FileInfo(); + try { - FileInfoItem infoItem = new FileInfoItem(fileInfo); - infoItem.Tag = fileInfo; - this.SearchResultList.Items.Add(infoItem); + fileInfo.FileType = (FileType)System.Enum.Parse(typeof(FileType), fileTypeField.StringValue); + } + catch + { + fileInfo.FileType = FileType.文本文件; + } + fileInfo.FileName = fileNameField.StringValue; + fileInfo.FilePath = filePathField.StringValue; + fileInfo.Breviary = breviaryField.StringValue; + fileInfo.FileSize = long.Parse(fileSizeField.StringValue); + fileInfo.CreateTime = createTimeField.StringValue; + fileInfo.Keywords = keywords; + + Dispatcher.BeginInvoke(new Action(() => { + SearchResultList.Items.Add(new FileInfoItem(fileInfo) + { + Tag = fileInfo + }); })); - resultNum++; } - string msg = "检索完成!共检索到" + resultNum + "个符合条件的结果(只显示前" + num + "条)。耗时:" + (DateTime.Now - beginMark).TotalSeconds + "秒。"; + string msg = "检索完成。分词:( " + text + " ),结果:" + resultNum + "个符合条件的结果(仅显示前" + AppConst.MAX_COUNT_LIMIT + "条),耗时:" + taskMark.ConsumeTime + "秒。"; - this.Dispatcher.BeginInvoke(new Action(() => - { + log.Debug(msg); + + Dispatcher.BeginInvoke(new Action(() => { Message.ShowSuccess("MessageContainer", msg); - })); + })); ShowStatus(msg); } finally { - if (searcher != null) - searcher.Dispose(); + try + { + if (searcher != null) + searcher.Dispose(); - if (reader != null) - reader.Dispose(); + if (reader != null) + reader.Dispose(); + } + catch { } } }); + t.Priority = ThreadPriority.Highest; + t.Start(); } #endregion @@ -375,9 +416,9 @@ namespace TextLocator } // 搜索按钮时,下拉框和其他筛选条件全部恢复默认值 - this.MatchWords.IsChecked = false; - this.OnlyFileName.IsChecked = false; - this.FileTypeFilter.SelectedIndex = 0; + MatchWords.IsChecked = false; + OnlyFileName.IsChecked = false; + FileTypeFilter.SelectedIndex = 0; BeforeSearch(); } @@ -391,19 +432,44 @@ namespace TextLocator { if (e.Key == Key.Enter) { + // 光标移除文本框 SearchText.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next)); // 搜索按钮时,下拉框和其他筛选条件全部恢复默认值 - this.MatchWords.IsChecked = false; - this.OnlyFileName.IsChecked = false; - this.FileTypeFilter.SelectedIndex = 0; + MatchWords.IsChecked = false; + OnlyFileName.IsChecked = false; + FileTypeFilter.SelectedIndex = 0; BeforeSearch(); + // 光标聚焦 SearchText.Focus(); } } + /// + /// 文本内容变化时 + /// + /// + /// + private void SearchText_TextChanged(object sender, TextChangedEventArgs e) + { + try + { + // 搜索关键词 + string text = SearchText.Text; + + // 替换特殊字符 + text = AppConst.REGIX_SPECIAL_CHARACTER.Replace(text, ""); + + // 回写处理过的字符 + SearchText.Text = text; + + // 光标定位到最后 + SearchText.SelectionStart = SearchText.Text.Length; + } catch { } + } + /// /// 文件类型过滤选中 /// @@ -474,13 +540,13 @@ namespace TextLocator Entity.FileInfo fileInfo = infoItem.Tag as Entity.FileInfo; // 根据文件类型显示图标 - this.PreviewFileTypeIcon.Source = FileUtil.GetFileIcon(fileInfo.FileType); - this.PreviewFileName.Text = fileInfo.FileName; - this.PreviewFileContent.Document.Blocks.Clear(); + PreviewFileTypeIcon.Source = FileUtil.GetFileIcon(fileInfo.FileType); + PreviewFileName.Text = fileInfo.FileName; + PreviewFileContent.Document.Blocks.Clear(); // 绑定打开文件和打开路径的Tag - this.OpenFile.Tag = fileInfo.FilePath; - this.OpenFolder.Tag = fileInfo.FilePath.Replace(fileInfo.FileName, ""); + OpenFile.Tag = fileInfo.FilePath; + OpenFolder.Tag = fileInfo.FilePath.Replace(fileInfo.FileName, ""); // 判断文件大小,超过2m的文件不预览 if (FileUtil.OutOfRange(fileInfo.FileSize)) @@ -495,9 +561,10 @@ namespace TextLocator // 图片文件 if (FileType.常用图片.GetDescription().Contains(fileExt)) { - this.PreviewFileContent.Visibility = Visibility.Hidden; - this.PreviewImage.Visibility = Visibility.Visible; - ThreadPool.QueueUserWorkItem(_ => { + PreviewFileContent.Visibility = Visibility.Hidden; + PreviewImage.Visibility = Visibility.Visible; + Thread t = new Thread(new ThreadStart(() => + { BitmapImage bi = new BitmapImage(); bi.BeginInit(); bi.CacheOption = BitmapCacheOption.OnLoad; @@ -505,22 +572,25 @@ namespace TextLocator bi.EndInit(); bi.Freeze(); - this.Dispatcher.BeginInvoke(new Action(() => { - this.PreviewImage.Source = bi; + Dispatcher.BeginInvoke(new Action(() => + { + PreviewImage.Source = bi; })); - }); + })); + t.Priority = ThreadPriority.AboveNormal; + t.Start(); } else { - this.PreviewImage.Visibility = Visibility.Hidden; - this.PreviewFileContent.Visibility = Visibility.Visible; + PreviewImage.Visibility = Visibility.Hidden; + PreviewFileContent.Visibility = Visibility.Visible; // 文件内容预览 - ThreadPool.QueueUserWorkItem(_ => + Thread t = new Thread(new ThreadStart(() => { string content = ""; - if (SimpleCacheUtil.Exsits(fileInfo.FilePath)) + if (CacheUtil.Exsits(fileInfo.FilePath)) { - content = SimpleCacheUtil.Get(fileInfo.FilePath); + content = CacheUtil.Get(fileInfo.FilePath); } else { @@ -528,18 +598,23 @@ namespace TextLocator content = FileInfoServiceFactory.GetFileInfoService(fileInfo.FileType).GetFileContent(fileInfo.FilePath); // 写入缓存 - SimpleCacheUtil.Add(fileInfo.FilePath, content); + CacheUtil.Add(fileInfo.FilePath, content); } - this.Dispatcher.BeginInvoke(new Action(() => + // 填充数据 + Dispatcher.Invoke(new Action(() => { - // 填充数据 - RichTextBoxUtil.FillingData(this.PreviewFileContent, content, new SolidColorBrush(Colors.Black)); - - // 关键词高亮 - RichTextBoxUtil.Highlighted(this.PreviewFileContent, Colors.Red, fileInfo.Keywords); + RichTextBoxUtil.FillingData(PreviewFileContent, content, new SolidColorBrush(Colors.Black)); })); - }); + + // 关键词高亮 + Dispatcher.InvokeAsync(() => + { + RichTextBoxUtil.Highlighted(PreviewFileContent, Colors.Red, fileInfo.Keywords); + }); + })); + t.Priority = ThreadPriority.AboveNormal; + t.Start(); } } @@ -565,8 +640,9 @@ namespace TextLocator Message.ShowWarning("MessageContainer", "索引构建中,请稍等。"); return; } + build = true; - ShowStatus("开始更新索引..."); + ShowStatus("开始更新索引,请稍等..."); BuildIndex(false); } @@ -594,7 +670,7 @@ namespace TextLocator } build = true; - ShowStatus("开始重建索引..."); + ShowStatus("开始重建索引,请稍等..."); BuildIndex(true); } @@ -624,11 +700,11 @@ namespace TextLocator /// private void OpenFile_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e) { - if (this.OpenFile.Tag != null) + if (OpenFile.Tag != null) { try { - System.Diagnostics.Process.Start(this.OpenFile.Tag + ""); + System.Diagnostics.Process.Start(OpenFile.Tag + ""); } catch (Exception ex) { @@ -644,11 +720,11 @@ namespace TextLocator /// private void OpenFolder_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e) { - if (this.OpenFolder.Tag != null) + if (OpenFolder.Tag != null) { try { - System.Diagnostics.Process.Start("explorer.exe", @"" + this.OpenFolder.Tag); + System.Diagnostics.Process.Start("explorer.exe", @"" + OpenFolder.Tag); } catch (Exception ex) { @@ -665,17 +741,20 @@ namespace TextLocator /// private List GetTextKeywords() { - string text = this.SearchText.Text; - if (string.IsNullOrEmpty(text)) - { - return null; - } + string text = SearchText.Text.Trim(); + // 为空直接返回null + if (string.IsNullOrEmpty(text)) return null; + List keywords = new List(); if (text.IndexOf(" ") != -1) { string[] texts = text.Split(' '); foreach (string txt in texts) { + if (string.IsNullOrEmpty(txt)) + { + continue; + } keywords.Add(txt); } } @@ -691,19 +770,19 @@ namespace TextLocator /// private void CleanSearchResult() { - this.FileTypeFilter.SelectedIndex = 0; - this.SearchText.Text = ""; - this.SearchResultList.Items.Clear(); - - this.OpenFile.Tag = null; - this.OpenFolder.Tag = null; - this.PreviewFileName.Text = ""; - this.PreviewFileContent.Document.Blocks.Clear(); - this.PreviewImage.Source = null; - - this.WorkStatus.Text = "就绪"; - this.OnlyFileName.IsChecked = false; - this.MatchWords.IsChecked = false; + FileTypeFilter.SelectedIndex = 0; + SearchText.Text = ""; + SearchResultList.Items.Clear(); + + OpenFile.Tag = null; + OpenFolder.Tag = null; + PreviewFileName.Text = ""; + PreviewFileContent.Document.Blocks.Clear(); + PreviewImage.Source = null; + + WorkStatus.Text = "就绪"; + OnlyFileName.IsChecked = false; + MatchWords.IsChecked = false; } /// @@ -711,7 +790,7 @@ namespace TextLocator /// private void BeforeSearch() { - object filter = this.FileTypeFilter.SelectedValue; + object filter = FileTypeFilter.SelectedValue; if (filter == null || filter.Equals("全部")) { filter = null; @@ -724,21 +803,26 @@ namespace TextLocator { return; } - if (build) + /*if (build) { Message.ShowWarning("MessageContainer", "索引构建中,请稍等。"); return; - } + }*/ // 清空预览信息 - this.OpenFile.Tag = null; - this.OpenFolder.Tag = null; - this.PreviewFileName.Text = ""; - this.PreviewFileContent.Document.Blocks.Clear(); - this.PreviewImage.Source = null; + OpenFile.Tag = null; + OpenFolder.Tag = null; + PreviewFileName.Text = ""; + PreviewFileContent.Document.Blocks.Clear(); + PreviewImage.Source = null; // 搜索 - Search(keywords, (filter == null ? null : filter + ""), (bool)this.OnlyFileName.IsChecked, (bool)this.MatchWords.IsChecked); + Search( + keywords, + filter == null ? null : filter + "", + (bool)OnlyFileName.IsChecked, + (bool)MatchWords.IsChecked + ); } #endregion } diff --git a/TextLocator/Properties/AssemblyInfo.cs b/TextLocator/Properties/AssemblyInfo.cs index 32e88df016ea94a7ff4d224a7e7f6899ffac07b1..ff8e71d7cd4897102fb825d923c4af3e243d52a5 100644 --- a/TextLocator/Properties/AssemblyInfo.cs +++ b/TextLocator/Properties/AssemblyInfo.cs @@ -50,7 +50,7 @@ using System.Windows; //通过使用 "*",如下所示: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.1.0")] -[assembly: AssemblyFileVersion("1.1.0")] +[assembly: AssemblyFileVersion("1.1.0.13")] // log4net [assembly: log4net.Config.XmlConfigurator(Watch = true)] \ No newline at end of file diff --git a/TextLocator/Service/DevelopFileService.cs b/TextLocator/Service/DevelopFileService.cs index f2b8d6b3b1470f370beab0e7b03efa50f397016a..9a3dc35b8329289f3866a0e31db250d208b640fe 100644 --- a/TextLocator/Service/DevelopFileService.cs +++ b/TextLocator/Service/DevelopFileService.cs @@ -3,6 +3,7 @@ using System; using System.IO; using System.Text; using System.Text.RegularExpressions; +using TextLocator.Core; namespace TextLocator.Service { @@ -21,30 +22,27 @@ namespace TextLocator.Service string extName = Path.GetExtension(filePath); // 文件内容 string content = ""; - lock (locker) + try { - try + using (StreamReader reader = new StreamReader(new FileStream(filePath, FileMode.Open), Encoding.UTF8)) { - using (StreamReader reader = new StreamReader(new FileStream(filePath, FileMode.Open), Encoding.UTF8)) + StringBuilder builder = new StringBuilder(); + string line; + while ((line = reader.ReadLine()) != null) { - StringBuilder builder = new StringBuilder(); - string line; - while ((line = reader.ReadLine()) != null) - { - builder.Append(line); - } + builder.Append(line); + } - content = Regex.Replace(builder.ToString(), "\\<.[^<>]*\\>", ""); + content = AppConst.REGIX_TAG.Replace(builder.ToString(), ""); - reader.Close(); - reader.Dispose(); - } - } - catch (Exception ex) - { - log.Error(ex.Message, ex); + reader.Close(); + reader.Dispose(); } } + catch (Exception ex) + { + log.Error(ex.Message, ex); + } return content; } } diff --git a/TextLocator/Service/ExcelFileService.cs b/TextLocator/Service/ExcelFileService.cs index 5524a859fce995eef95a76908b6e60d7372c1a2f..726ce53ee723e0d7cb2e408c61413bfc6426f75b 100644 --- a/TextLocator/Service/ExcelFileService.cs +++ b/TextLocator/Service/ExcelFileService.cs @@ -94,38 +94,44 @@ namespace TextLocator.Service } catch { - // =========== Spire.XLS =========== - // 创建Workbook对象 - using (Spire.Xls.Workbook workbook = new Spire.Xls.Workbook()) + try { - - // 加载Excel文档 - workbook.LoadFromFile(filePath); - - StringBuilder builder = new StringBuilder(); - - // 获取工作表 - for (int i = 0; i < workbook.Worksheets.Count; i++) + // =========== Spire.XLS =========== + // 创建Workbook对象 + using (Spire.Xls.Workbook workbook = new Spire.Xls.Workbook()) { - Spire.Xls.Worksheet sheet = workbook.Worksheets[i]; + // 加载Excel文档 + workbook.LoadFromFile(filePath); - // 行 - for (int j = sheet.FirstRow; j < sheet.LastRow; j++) + StringBuilder builder = new StringBuilder(); + + // 获取工作表 + for (int i = 0; i < workbook.Worksheets.Count; i++) { - Spire.Xls.CellRange row = sheet.Rows[j]; - // 列 - for (int k = 0; k < row.Columns.Length; k++) + Spire.Xls.Worksheet sheet = workbook.Worksheets[i]; + + // 行 + for (int j = sheet.FirstRow; j < sheet.LastRow; j++) { - builder.Append(row.Columns[k].Value2.ToString()); + Spire.Xls.CellRange row = sheet.Rows[j]; + // 列 + for (int k = 0; k < row.Columns.Length; k++) + { + builder.Append(row.Columns[k].Value2.ToString()); + } + row.Dispose(); + builder.AppendLine(); } - row.Dispose(); - builder.AppendLine(); + sheet.Dispose(); } - sheet.Dispose(); - } - workbook.Dispose(); + workbook.Dispose(); - content = builder.ToString(); + content = builder.ToString(); + } + } + catch (Exception ex) + { + log.Error(ex.Message, ex); } } } diff --git a/TextLocator/Service/TxtFileService.cs b/TextLocator/Service/TxtFileService.cs index 063219adb3216ed508aa6d0ee66e698587e4ac84..06cb67d4c5dacddb70bdde1d198f92dcb80a133e 100644 --- a/TextLocator/Service/TxtFileService.cs +++ b/TextLocator/Service/TxtFileService.cs @@ -18,28 +18,25 @@ namespace TextLocator.Service { // 文件内容 string content = ""; - lock (locker) + try { - try + using (StreamReader reader = new StreamReader(filePath, Encoding.UTF8)) { - using (StreamReader reader = new StreamReader(filePath, Encoding.UTF8)) + StringBuilder builder = new StringBuilder(); + string line; + while ((line = reader.ReadLine()) != null) { - StringBuilder builder = new StringBuilder(); - string line; - while ((line = reader.ReadLine()) != null) - { - builder.Append(line); - } - reader.Close(); - reader.Dispose(); - - content = builder.ToString(); + builder.Append(line); } + reader.Close(); + reader.Dispose(); + + content = builder.ToString(); } - catch (Exception ex) - { - log.Error(ex.Message, ex); - } + } + catch (Exception ex) + { + log.Error(ex.Message, ex); } return content; } diff --git a/TextLocator/Service/XmlFileService.cs b/TextLocator/Service/XmlFileService.cs index da3f721c54ffa0f65140f35d3c28a1bd34b079ee..fad755c2062cf6e0904d32426a30da0a67b3f9cc 100644 --- a/TextLocator/Service/XmlFileService.cs +++ b/TextLocator/Service/XmlFileService.cs @@ -3,6 +3,7 @@ using System; using System.IO; using System.Text; using System.Text.RegularExpressions; +using TextLocator.Core; namespace TextLocator.Service { @@ -19,30 +20,27 @@ namespace TextLocator.Service { // 文件内容 string content = ""; - lock (locker) + try { - try + using (StreamReader reader = new StreamReader(new FileStream(filePath, FileMode.Open), Encoding.UTF8)) { - using (StreamReader reader = new StreamReader(new FileStream(filePath, FileMode.Open), Encoding.UTF8)) + StringBuilder builder = new StringBuilder(); + string line; + while ((line = reader.ReadLine()) != null) { - StringBuilder builder = new StringBuilder(); - string line; - while ((line = reader.ReadLine()) != null) - { - builder.Append(line); - } + builder.Append(line); + } - content = Regex.Replace(builder.ToString(), "\\<.[^<>]*\\>", ""); + content = AppConst.REGIX_TAG.Replace(builder.ToString(), ""); - reader.Close(); - reader.Dispose(); - } - } - catch (Exception ex) - { - log.Error(ex.Message, ex); + reader.Close(); + reader.Dispose(); } } + catch (Exception ex) + { + log.Error(ex.Message, ex); + } return content; } } diff --git a/TextLocator/TextLocator.csproj b/TextLocator/TextLocator.csproj index c85f93c0ebcf81165bf5963fa8ad843869fd52a7..223716b6ffd7708f80b4557c299e673e196940c6 100644 --- a/TextLocator/TextLocator.csproj +++ b/TextLocator/TextLocator.csproj @@ -155,6 +155,7 @@ + @@ -187,9 +188,10 @@ - + + Designer diff --git a/TextLocator/Util/AppUtil.cs b/TextLocator/Util/AppUtil.cs index c70d3925c815d52c5bc2307fb6141cf3b67315ab..82eca010c00ebb89bb599c651eabd2aabe78b095 100644 --- a/TextLocator/Util/AppUtil.cs +++ b/TextLocator/Util/AppUtil.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; +using System.Threading; using System.Threading.Tasks; namespace TextLocator.Util @@ -17,6 +18,12 @@ namespace TextLocator.Util { private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// 锁 + /// + private static object locker = new object(); + /// /// 应用目录 /// @@ -29,11 +36,28 @@ namespace TextLocator.Util /// App.ini路径:_AppDir\\_AppName.ini /// private static readonly string _AppIniFile = _AppDir + "\\" + _AppName + ".ini"; + + /// + /// Ini文件内容缓存 + /// + private static readonly Dictionary _AppIniCache = new Dictionary(); static AppUtil() { log.Info("当前App的ini文件路径为:" + _AppIniFile); + // ini文件初始化 + Initialize(); + + // 加载节点下全部Key-Value + LoadAllKeyValue("FileIndex"); + } + + /// + /// 初始化 + /// + private static void Initialize() + { try { DirectoryInfo dir = new DirectoryInfo(_AppIniFile.Substring(0, _AppIniFile.LastIndexOf("\\"))); @@ -61,11 +85,30 @@ namespace TextLocator.Util /// 缓冲区 /// 键 /// 值 - public static void WriteIni(string section, string key, string value) + public static void WriteValue(string section, string key, string value) { try { - WritePrivateProfileString(section, key, value, _AppIniFile); + if (string.IsNullOrEmpty(section)) + { + throw new ArgumentException("必须指定节点名称", "section"); + } + + if (string.IsNullOrEmpty(key)) + { + throw new ArgumentException("必须指定键名称(key)", "key"); + } + if (value == null) + { + throw new ArgumentException("值不能为null", "value"); + } + + lock (locker) + { + _AppIniCache[GetCacheKey(section, key)] = value; + + WritePrivateProfileString(section, key, value, _AppIniFile); + } } catch (Exception ex) { @@ -79,14 +122,35 @@ namespace TextLocator.Util /// 缓冲区 /// 键 /// - public static string ReadIni(string section, string key, string def = "") + public static string ReadValue(string section, string key, string def = "") { try { - StringBuilder temp = new StringBuilder(255); - int i = GetPrivateProfileString(section, key, def, temp, 255, _AppIniFile); + const int SIZE = 1024 * 10; + + if (string.IsNullOrEmpty(section)) + { + throw new ArgumentException("必须指定节点名称", "section"); + } - return temp.ToString(); + if (string.IsNullOrEmpty(key)) + { + throw new ArgumentException("必须指定键名称(key)", "key"); + } + lock (locker) + { + if (_AppIniCache.ContainsKey(GetCacheKey(section, key))) + { + return _AppIniCache[GetCacheKey(section, key)]; + } + } + StringBuilder builder = new StringBuilder(SIZE); + uint bytesReturned = GetPrivateProfileString(section, key, def, builder, SIZE, _AppIniFile); + if (bytesReturned != 0) + { + return builder.ToString(); + } + return def; } catch (Exception ex) { @@ -94,28 +158,123 @@ namespace TextLocator.Util return def; } } + /// - /// Win32API:写入配置 + /// 删除指定的节点。 /// - /// - /// - /// - /// + /// 节点 + /// 操作是否成功 + public static void DeleteSection(string section) + { + try + { + if (string.IsNullOrEmpty(section)) + { + throw new ArgumentException("必须指定节点名称", "section"); + } + WritePrivateProfileString(section, null, null, _AppIniFile); + } + catch (Exception ex) + { + log.Error(ex.Message); + } + } + + /// + /// 加载节点下全部KeyValue + /// + /// 节点 /// - [DllImport("kernel32")] //返回0表示失败,非0为成功 - private static extern long WritePrivateProfileString(string section, string key, string val, string filePath); + private static void LoadAllKeyValue(string section) + { + Thread t = new Thread(() => + { + try + { + // 默认为32767 + uint MAX_BUFFER = 32767; + // 返回值[返回值形式为 key=value,例如 Color=Red] + string[] items = new string[0]; + + //分配内存 + IntPtr pReturnedString = Marshal.AllocCoTaskMem((int)MAX_BUFFER * sizeof(char)); + + uint bytesReturned = GetPrivateProfileSection(section, pReturnedString, MAX_BUFFER, _AppIniFile); + + if (!(bytesReturned == MAX_BUFFER - 2) || (bytesReturned == 0)) + { + string returnedString = Marshal.PtrToStringAuto(pReturnedString, (int)bytesReturned); + items = returnedString.Split(new char[] { '\0' }, StringSplitOptions.RemoveEmptyEntries); + } + + // 释放内存 + Marshal.FreeCoTaskMem(pReturnedString); + + foreach (string entry in items) + { + string[] v = entry.Split('='); + + _AppIniCache[GetCacheKey(section, v[0])] = v[1]; + } + log.Debug("加载" + section + "节点下全部键值,总数:" + _AppIniCache.Count); + } catch { } + }); + t.Priority = ThreadPriority.AboveNormal; + t.Start(); + } + /// - /// Win32API:读取配置 + /// 获取缓存Key(节点名称 + Key) /// /// /// - /// - /// - /// - /// /// - [DllImport("kernel32")] //返回取得字符串缓冲区的长度 - private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath); + private static string GetCacheKey(string section, string key) + { + return section + "_" + key; + } + /// + /// 将指定的键和值写到指定的节点,如果已经存在则替换 + /// + /// 节点名称 + /// 键名称。如果为null,则删除指定的节点及其所有的项目 + /// 值内容。如果为null,则删除指定节点中指定的键。 + /// INI文件 + /// 操作是否成功 + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool WritePrivateProfileString(string lpAppName, string lpKeyName, string lpString, string lpFileName); + /// + /// 读取INI文件中指定的Key的值 + /// + /// 节点名称。如果为null,则读取INI中所有节点名称,每个节点名称之间用\0分隔 + /// Key名称。如果为null,则读取INI中指定节点中的所有KEY,每个KEY之间用\0分隔 + /// 读取失败时的默认值 + /// 读取的内容缓冲区,读取之后,多余的地方使用\0填充 + /// 内容缓冲区的长度 + /// INI文件名 + /// 实际读取到的长度 + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + private static extern uint GetPrivateProfileString(string lpAppName, string lpKeyName, string lpDefault, [In, Out] char[] lpReturnedString, uint nSize, string lpFileName); + + //另一种声明方式,使用 StringBuilder 作为缓冲区类型的缺点是不能接受\0字符,会将\0及其后的字符截断, + //所以对于lpAppName或lpKeyName为null的情况就不适用 + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + private static extern uint GetPrivateProfileString(string lpAppName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, uint nSize, string lpFileName); + + //再一种声明,使用string作为缓冲区的类型同char[] + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + private static extern uint GetPrivateProfileString(string lpAppName, string lpKeyName, string lpDefault, string lpReturnedString, uint nSize, string lpFileName); + /// + /// 获取某个指定节点(Section)中所有KEY和Value + /// + /// 节点名称 + /// 返回值的内存地址,每个之间用\0分隔 + /// 内存大小(characters) + /// Ini文件 + /// 内容的实际长度,为0表示没有内容,为nSize-2表示内存大小不够 + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + private static extern uint GetPrivateProfileSection(string lpAppName, IntPtr lpReturnedString, uint nSize, string lpFileName); #endregion } } diff --git a/TextLocator/Util/SimpleCacheUtil.cs b/TextLocator/Util/CacheUtil.cs similarity index 75% rename from TextLocator/Util/SimpleCacheUtil.cs rename to TextLocator/Util/CacheUtil.cs index 66cc0aeebb184084d8ae5af9d1c215f94a2bd7bc..46bdfb09549cb26c6ee5a17acfb08234c32321f1 100644 --- a/TextLocator/Util/SimpleCacheUtil.cs +++ b/TextLocator/Util/CacheUtil.cs @@ -9,17 +9,17 @@ namespace TextLocator.Util /// /// 简单缓存工具类 /// - public class SimpleCacheUtil + public class CacheUtil { //缓存容器 - private static Dictionary simpleCacheDic = new Dictionary(); + private static Dictionary cacheDic = new Dictionary(); /// /// 添加缓存 /// public static void Add(string key, object value) { - simpleCacheDic.Add(key, value); + cacheDic[key] = value; } /// @@ -29,7 +29,7 @@ namespace TextLocator.Util { try { - return (T)simpleCacheDic[key]; + return (T)cacheDic[key]; } catch { } return default(T); } @@ -41,7 +41,7 @@ namespace TextLocator.Util /// public static bool Exsits(string key) { - return simpleCacheDic.ContainsKey(key); + return cacheDic.ContainsKey(key); } } } diff --git a/TextLocator/Util/FileUtil.cs b/TextLocator/Util/FileUtil.cs index b419d3351e6677cd8044775929f1e3194b6eda0e..64b234cb91d8c555458954193a3950840b3b6a55 100644 --- a/TextLocator/Util/FileUtil.cs +++ b/TextLocator/Util/FileUtil.cs @@ -114,11 +114,6 @@ namespace TextLocator.Util public static bool OutOfRange(long fileSize, int range = 10) { return false; - /*if (fileSize <= 0) - { - return false; - } - return fileSize / 1024 / 1024 > range;*/ } /// @@ -128,39 +123,111 @@ namespace TextLocator.Util /// 文档列表 public static void GetAllFiles(string rootPath, List filePaths) { - DirectoryInfo dir = new DirectoryInfo(rootPath); - // 得到所有子目录 + // 根目录 + DirectoryInfo rootDir = new DirectoryInfo(rootPath); + + // 文件夹处理 try { string[] dirs = Directory.GetDirectories(rootPath); - foreach (string di in dirs) + foreach (string dir in dirs) { + string du = dir.ToUpper(); + // $开始、360REC开头、SYSTEM、TEMP + if (du.Contains("$RECYCLE") || du.Contains("360REC") || du.Contains("SYSTEM") || du.Contains("TEMP")) + { + continue; + } // 递归调用 - GetAllFiles(di, filePaths); + GetAllFiles(dir, filePaths); } } - catch (Exception ex) - { - log.Error(ex.Message, ex); - } + catch { } + // 文件处理 try { - string regex = @"^.+\.(" + FileTypeUtil.GetFileTypeExts("|") + ")$"; - // 查找word文件 - string[] paths = Directory.GetFiles(dir.FullName) - .Where(file => Regex.IsMatch(file, regex)) + string[] paths = Directory.GetFiles(rootDir.FullName) + .Where(file => AppConst.REGIX_FILE_EXT.IsMatch(file)) .ToArray(); // 遍历每个文档 foreach (string path in paths) { + string fileName = path.Substring(path.LastIndexOf("\\") + 1); + if (fileName.StartsWith("`") || fileName.StartsWith("$")) + { + continue; + } filePaths.Add(path); } } - catch (Exception ex) + catch { } + } + + /// + /// 删除目录下全部文件 + /// + /// + public static void RemoveDirectory(string srcDir) + { + // 若目标文件夹不存在 + if (!Directory.Exists(srcDir)) { - log.Error(ex.Message, ex); + return; + } + // 获取源文件夹中的所有文件完整路径 + FileInfo[] files = new DirectoryInfo(srcDir).GetFiles(); + foreach (FileInfo fileInfo in files) + { + try + { + File.Delete(fileInfo.FullName); + } + catch (Exception ex) + { + log.Error("索引清理失败:" + ex.Message, ex); + } + } + } + + /// + /// 拷贝源目录到新目录 + /// + /// + /// + public static void CopyDirectory(string srcDir, string destDir) + { + // 若目标文件夹不存在 + if (!Directory.Exists(destDir)) + { + // 创建目标文件夹 + Directory.CreateDirectory(destDir); + } + string newPath; + + // 获取源文件夹中的所有文件完整路径 + FileInfo[] files = new DirectoryInfo(srcDir).GetFiles(); + // 遍历文件 + foreach (FileInfo fileInfo in files) + { + newPath = destDir + "\\" + fileInfo.Name; + try + { + File.Copy(fileInfo.FullName, newPath, true); + } + catch (Exception ex) + { + log.Error("索引拷贝错误:" + ex.Message, ex); + } + } + string[] dirs = Directory.GetDirectories(srcDir); + // 遍历文件夹 + foreach (string path in dirs) + { + DirectoryInfo directory = new DirectoryInfo(path); + string newDir = destDir + directory.Name; + CopyDirectory(path + "\\", newDir + "\\"); } } } diff --git a/TextLocator/Util/MD5Util.cs b/TextLocator/Util/MD5Util.cs new file mode 100644 index 0000000000000000000000000000000000000000..cd9988d9723c9ca6102ed1c99b387efcc9fef029 --- /dev/null +++ b/TextLocator/Util/MD5Util.cs @@ -0,0 +1,53 @@ +using System.Security.Cryptography; +using System.Text; + +namespace TextLocator.Util +{ + /// + /// MD5工具类 + /// + public class MD5Util + { + /// + /// 获取MD5值 + /// + /// + /// + public static string GetMD5Hash(string value) + { + //就是比string往后一直加要好的优化容器 + StringBuilder sb = new StringBuilder(); + using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider()) + { + //将输入字符串转换为字节数组并计算哈希。 + byte[] data = md5.ComputeHash(Encoding.UTF8.GetBytes(value)); + + //X为 十六进制 X都是大写 x都为小写 + //2为 每次都是两位数 + //假设有两个数10和26,正常情况十六进制显示0xA、0x1A,这样看起来不整齐,为了好看,可以指定"X2",这样显示出来就是:0x0A、0x1A。 + //遍历哈希数据的每个字节 + //并将每个字符串格式化为十六进制字符串。 + int length = data.Length; + for (int i = 0; i < length; i++) + sb.Append(data[i].ToString("X2")); + + } + return sb.ToString(); + } + + /// + /// 验证MD5值 + /// + /// + /// + /// + public static bool VerifyMD5Hash(string value, string hash) + { + string hashOfInput = GetMD5Hash(value); + if (hashOfInput.CompareTo(hash) == 0) + return true; + else + return false; + } + } +} diff --git "a/\346\226\207\346\234\254\345\256\232\344\275\215\345\231\250\350\221\227\344\275\234\346\235\203.zip" "b/\346\226\207\346\234\254\345\256\232\344\275\215\345\231\250\350\221\227\344\275\234\346\235\203.zip" new file mode 100644 index 0000000000000000000000000000000000000000..f3220b241db944b3cdbe1017284cbcb58d7c93c7 Binary files /dev/null and "b/\346\226\207\346\234\254\345\256\232\344\275\215\345\231\250\350\221\227\344\275\234\346\235\203.zip" differ