diff --git a/README.md b/README.md index 633a52623a8f37782f72641586ad63d3766900ae..407f0479bfadc03aef7a575df39a9fe5e4db0fc7 100644 --- a/README.md +++ b/README.md @@ -50,5 +50,5 @@ 9. [Hardcodet.NotifyIcon.Wpf](https://www.nuget.org/packages/Hardcodet.NotifyIcon.Wpf/) #### 仓库地址 -[github](https://github.com/liulei901112/TextLocator) -[gitee](https://gitee.com/liulei901112/TextLocator) \ No newline at end of file +* [github](https://github.com/liulei901112/TextLocator) +* [gitee](https://gitee.com/liulei901112/TextLocator) \ No newline at end of file diff --git a/TextLocator/App.xaml.cs b/TextLocator/App.xaml.cs index a96c8b7f05e3a96317f22d9f9f70a4a5749ae085..50b6dee7a14bb72fd0b2186af0646edb44ab40af 100644 --- a/TextLocator/App.xaml.cs +++ b/TextLocator/App.xaml.cs @@ -35,7 +35,10 @@ namespace TextLocator // 初始化线程池大小 InitThreadPoolSize(); - // 初始化文件信息服务引擎 + // 初始化配置 + InitAppConfig(); + + // 初始化文件服务引擎 InitFileInfoServiceEngine(); } @@ -93,7 +96,6 @@ namespace TextLocator AppUtil.WriteValue("ThreadPool", "MaxSize", AppConst.THREAD_POOL_MAX_SIZE + ""); } - /// /// 初始化文件信息服务引擎 /// @@ -124,6 +126,15 @@ namespace TextLocator log.Error("文件服务工厂初始化错误:" + ex.Message, ex); } } + + /// + /// 初始化AppConfig + /// + private void InitAppConfig() + { + // 保存线程池 + AppUtil.WriteValue("AppConfig", "FileReadTimeout", AppConst.FILE_READ_TIMEOUT + ""); + } #endregion #region 异常处理 diff --git a/TextLocator/Core/AppConst.cs b/TextLocator/Core/AppConst.cs index 8c39bc3c6a1c234f351766c2a030dd630f680487..fa4a0cf6f11ccf172b98191c6d0702c3a92f3d9c 100644 --- a/TextLocator/Core/AppConst.cs +++ b/TextLocator/Core/AppConst.cs @@ -21,13 +21,9 @@ namespace TextLocator.Core /// public static readonly int THREAD_POOL_MAX_SIZE = int.Parse(AppUtil.ReadValue("ThreadPool", "MaxSize", "64")); /// - /// 应用目录 - /// - public static readonly string APP_DIR = AppDomain.CurrentDomain.BaseDirectory; - /// /// App.ini路径:_AppDir\\_AppName\\Index\\ /// - public static readonly string APP_INDEX_DIR = Path.Combine(APP_DIR, "Index"); + public static readonly string APP_INDEX_DIR = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Index"); /// /// 分词器 /// new Lucene.Net.Analysis.Cn.ChineseAnalyzer(); @@ -50,6 +46,10 @@ namespace TextLocator.Core /// 搜索最大值限制 /// public static readonly int MAX_COUNT_LIMIT = int.Parse(AppUtil.ReadValue("AppConfig", "MaxCountLimit", "100")); + /// + /// 文件读取超时时间,单位:秒 + /// + public static readonly int FILE_READ_TIMEOUT = int.Parse(AppUtil.ReadValue("AppConfig", "FileReadTimeout", "600")); /// /// 匹配特殊字符 @@ -70,7 +70,7 @@ namespace TextLocator.Core /// /// 匹配排除关键词 /// - public static readonly Regex REGEX_EXCLUDE_KEYWORD = new Regex(@"(\$RECYCLE|360REC|C:\\(SYSTEM|PROGRAM FILES)|TEMP\\|TMP\\|SYSTEM VOLUME INFOMATION|\.(.*)\\|\{(.*)\})"); + public static readonly Regex REGEX_EXCLUDE_KEYWORD = new Regex(@"(\$RECYCLE|360REC|SYSTEM|TEMP|SYSTEM VOLUME INFOMATION|\{(.*)\})"); /// /// 匹配开始字符 /// @@ -88,5 +88,6 @@ namespace TextLocator.Core /// 文件内容缩略信息截取值 /// public const int FILE_CONTENT_SUB_LENGTH = 120; + } } diff --git a/TextLocator/Factory/FileInfoServiceFactory.cs b/TextLocator/Factory/FileInfoServiceFactory.cs index e9227dd18bdb382c56f52bf96be54b6ae259fef3..9464f368ddde8641f73456b604916a4ac8858a96 100644 --- a/TextLocator/Factory/FileInfoServiceFactory.cs +++ b/TextLocator/Factory/FileInfoServiceFactory.cs @@ -1,16 +1,20 @@ using log4net; using System; using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using TextLocator.Core; using TextLocator.Enums; using TextLocator.Service; +using TextLocator.Util; namespace TextLocator.Factory { - /// - /// 文件信息服务工厂 - /// - public class FileInfoServiceFactory - { + /// + /// 文件信息服务工厂 + /// + public class FileInfoServiceFactory + { private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); /// @@ -18,12 +22,40 @@ namespace TextLocator.Factory /// private static Dictionary services = new Dictionary(); + #region 工厂方法 + /// + /// 获取文件内容 + /// + /// + /// + public static string GetFileContent(string filePath) + { + // 获取文件服务对象 + IFileInfoService fileInfoService = GetFileInfoService(FileTypeUtil.GetFileType(filePath)); + + string content; + // 读取文件内容 + content = WaitTimeout(fileInfoService.GetFileContent, filePath, TimeSpan.FromSeconds(AppConst.FILE_READ_TIMEOUT)); + return content; + } + + /// + /// 注册服务实例 + /// + /// 文件类型 + /// 服务实例 + public static void Register(FileType fileType, IFileInfoService fileInfoService) + { + log.Debug((int)fileType + ":" + fileType.ToString() + " 引擎注册"); + services.Add(fileType, fileInfoService); + } + /// /// 根据项目类型获取服务实例 /// /// 文件类型 /// - public static IFileInfoService GetFileInfoService(FileType fileType) + private static IFileInfoService GetFileInfoService(FileType fileType) { try { @@ -35,16 +67,48 @@ namespace TextLocator.Factory throw new Exception("暂无[" + fileType.ToString() + "]服务实例, 返回默认其他类型文件服务实例"); } } + #endregion + #region 超时函数 /// - /// 注册服务实例 + /// 有参数,有反回值方法 /// - /// 文件类型 - /// 服务实例 - public static void Register(FileType fileType, IFileInfoService fileInfoService) + /// + /// + public delegate string TimeoutDelegate(string param); + + /// + /// 有参数,有反回值超时方法 + /// + /// 执行方法 + /// 超时时间 + /// 执行参数 + /// 反回一个string类型方法 + public static string WaitTimeout(TimeoutDelegate method, string param, TimeSpan timeout) { - log.Debug((int)fileType + ":" + fileType.ToString() + " 引擎注册"); - services.Add(fileType, fileInfoService); + string obj = null; + AutoResetEvent are = new AutoResetEvent(false); + Thread t = new Thread(delegate () { obj = method(param); are.Set(); }); + t.Start(); + Wait(t, timeout, are); + return obj; + } + + /// + /// 等待方法执行完成,或超时 + /// + /// + /// + /// + private static void Wait(Thread t, TimeSpan timeout, WaitHandle are) + { + WaitHandle[] ares = new WaitHandle[] { are }; + int index = WaitHandle.WaitAny(ares, timeout); + if ((index != 0) && t.IsAlive) // 如果不是执行完成的信号,并且,线程还在执行,那么,结束这个线程 + { + t.Abort(); + } } + #endregion } } diff --git a/TextLocator/Index/IndexCore.cs b/TextLocator/Index/IndexCore.cs index 1fa1fba9edea28d9e7a27f70bfa4f2154383573b..826cb2fbdd9455e7346a7df61f220ec687260836 100644 --- a/TextLocator/Index/IndexCore.cs +++ b/TextLocator/Index/IndexCore.cs @@ -1,5 +1,4 @@ using log4net; -using Lucene.Net.Documents; using Lucene.Net.Index; using System; using System.Collections.Generic; @@ -48,46 +47,37 @@ namespace TextLocator.Index /// /// 回调函数 /// - private static Callback _callback; - + private static volatile Callback _callback; #region 索引写入器 /// /// 索引写入初始化(FSDirectory表示索引存放在硬盘上,RAMDirectory表示放在内存上) /// - private static IndexWriter _indexWriter; - /// - /// 索引写入器锁 - /// - private static volatile object _writerLock = new object(); + private static volatile IndexWriter _indexWriter; + /// /// 创建索引写入器 /// - private static IndexWriter GetIndexWriter() + private static void CreateIndexWriter() { if (_indexWriter == null) { - lock(_writerLock) - { - if (_indexWriter == null) - { - // 索引写入初始化(FSDirectory表示索引存放在硬盘上,RAMDirectory表示放在内存上) - _indexWriter = new IndexWriter( - // 索引目录 - AppConst.INDEX_DIRECTORY, - // 分词器 - AppConst.INDEX_ANALYZER, - // 是否创建 - _create, - // 字段限制 - IndexWriter.MaxFieldLength.UNLIMITED); - - // 设置Buffer内存上限,默认值16MB - _indexWriter.SetRAMBufferSizeMB(512); - } - } + // 索引写入初始化(FSDirectory表示索引存放在硬盘上,RAMDirectory表示放在内存上) + _indexWriter = new IndexWriter( + // 索引目录 + AppConst.INDEX_DIRECTORY, + // 分词器 + AppConst.INDEX_ANALYZER, + // 是否创建 + _create, + // 字段限制 + IndexWriter.MaxFieldLength.UNLIMITED); + + // 设置Buffer内存上限,默认值16MB + _indexWriter.SetRAMBufferSizeMB(512); + // 设置Buffer内存文档上线 + _indexWriter.SetMaxBufferedDocs(10000); } - return _indexWriter; } /// @@ -95,20 +85,17 @@ namespace TextLocator.Index /// private static void CloseIndexWriter() { - lock (_writerLock) + if (_indexWriter != null) { - if (_indexWriter != null) - { - // 销毁索引写入器 - _indexWriter.Dispose(); - } + // 销毁索引写入器 + _indexWriter.Dispose(); + // 索引写入器置为NULL + _indexWriter = null; } - // 置为NULL - _indexWriter = null; } #endregion - #region 创建文件索引 + #region 创建索引 /// /// 创建索引 /// @@ -142,7 +129,7 @@ namespace TextLocator.Index } // 创建索引写入器 - GetIndexWriter(); + CreateIndexWriter(); using (MutipleThreadResetEvent resetEvent = new MutipleThreadResetEvent(_totalCount)) { @@ -155,34 +142,36 @@ namespace TextLocator.Index { continue; } - // 加入线程池 ThreadPool.QueueUserWorkItem(new WaitCallback(CreateIndexTask), new TaskInfo() { FilePath = filePath, ResetEvent = resetEvent }); - } + // 等待所有线程结束 resetEvent.WaitAll(); } - try + lock (locker) { - // 索引优化 - GetIndexWriter().Optimize(); + try + { + // 索引优化 + _indexWriter.Optimize(); + } + catch (Exception ex) + { + log.Error("索引优化错误:" + ex.Message, ex); + } - // 关闭并销毁索引写入器 + // 关闭索引写入器 CloseIndexWriter(); - - // 手动GC - ManualGC(); - } - catch (Exception ex) - { - log.Error(ex.Message, ex); } + + // 手动GC + ManualGC(); } /// @@ -203,16 +192,11 @@ namespace TextLocator.Index // 跳过的文件闪烁 _callback(skipMsg, CalcFinishRatio(_finishCount, _totalCount)); - lock (locker) - { - _finishCount++; - } + // 完成数量+1 + Interlocked.Increment(ref _finishCount); - try - { - resetEvent.SetOne(); - } - catch { } + // 当前任务执行完成,唤醒等待线程继续执行 + resetEvent.SetOne(); #if !DEBUG log.Debug(skipMsg); @@ -231,11 +215,12 @@ namespace TextLocator.Index TaskInfo taskInfo = obj as TaskInfo; try { - // 文件路径 - string filePath = taskInfo.FilePath; // 解析时间 var taskMark = TaskTime.StartNew(); + // 文件路径 + string filePath = taskInfo.FilePath; + // 写入已索引标记 AppUtil.WriteValue("FileIndex", filePath, "1"); @@ -251,98 +236,110 @@ namespace TextLocator.Index // 根据文件路径获取文件类型(自定义文件类型分类) FileType fileType = FileTypeUtil.GetFileType(filePath); - string filePathSub = filePath; - if (filePath.Length > 60) + // 截取文件路径 + string subFilePath = filePath; + if (subFilePath.Length > 65) { - filePathSub = filePath.Substring(0, 30) + "......" + filePath.Substring(filePath.Length - 30); + subFilePath = filePath.Substring(0, 30) + "......" + filePath.Substring(filePath.Length - 30); } - StringBuilder msg = new StringBuilder("[" + _finishCount * 1.0F + "/" + _totalCount + "] => 引擎:" + (int)fileType + ",文件:" + filePathSub); + StringBuilder msg = new StringBuilder("[" + _finishCount * 1.0F + "/" + _totalCount + "] => 引擎:" + (int)fileType + ",文件:" + subFilePath); // 文件内容 - string content = FileInfoServiceFactory.GetFileInfoService(fileType).GetFileContent(filePath); + string content = FileInfoServiceFactory.GetFileContent(filePath); msg.Append(",解析:" + taskMark.ConsumeTime + "秒"); - - // 缩略信息 - string breviary = AppConst.REGEX_LINE_BREAKS_AND_WHITESPACE.Replace(content, ""); - if (breviary.Length > AppConst.FILE_CONTENT_SUB_LENGTH) + // 判断文件内容 + if (!string.IsNullOrEmpty(content)) { - breviary = breviary.Substring(0, AppConst.FILE_CONTENT_SUB_LENGTH) + "..."; - } + // 缩略信息 + string breviary = AppConst.REGEX_LINE_BREAKS_AND_WHITESPACE.Replace(content, ""); + if (breviary.Length > AppConst.FILE_CONTENT_SUB_LENGTH) + { + breviary = breviary.Substring(0, AppConst.FILE_CONTENT_SUB_LENGTH) + "..."; + } - // 文件标记 - string fileMark = MD5Util.GetMD5Hash(filePath); //fileInfo.DirectoryName + fileInfo.CreationTime.ToString(); + // 文件标记 + string fileMark = MD5Util.GetMD5Hash(filePath); - // 索引时间 - taskMark = TaskTime.StartNew(); + // 索引时间 + taskMark = TaskTime.StartNew(); - lock (locker) - { - try + lock (locker) { - // 当索引文件中含有与filemark相等的field值时,会先删除再添加,以防出现重复 - // GetIndexWriter().DeleteDocuments(new Term("FileMark", fileMark)); - - Document doc = new Document(); + // 创建索引Doc对象 + Lucene.Net.Documents.Document doc = new Lucene.Net.Documents.Document(); // 不分词建索引 - doc.Add(new Field("FileMark", fileMark, Field.Store.YES, Field.Index.NOT_ANALYZED, Field.TermVector.YES)); - doc.Add(new Field("FileType", fileType.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED)); - doc.Add(new Field("FileSize", fileSize + "", Field.Store.YES, Field.Index.NOT_ANALYZED)); - doc.Add(new Field("Breviary", breviary, Field.Store.YES, Field.Index.NOT_ANALYZED)); - doc.Add(new Field("CreateTime", createTime, Field.Store.YES, Field.Index.NOT_ANALYZED)); + doc.Add(new Lucene.Net.Documents.Field("FileMark", fileMark, Lucene.Net.Documents.Field.Store.YES, Lucene.Net.Documents.Field.Index.NOT_ANALYZED)); + doc.Add(new Lucene.Net.Documents.Field("FileType", fileType.ToString(), Lucene.Net.Documents.Field.Store.YES, Lucene.Net.Documents.Field.Index.NOT_ANALYZED)); + doc.Add(new Lucene.Net.Documents.Field("FileSize", fileSize + "", Lucene.Net.Documents.Field.Store.YES, Lucene.Net.Documents.Field.Index.NOT_ANALYZED)); + doc.Add(new Lucene.Net.Documents.Field("Breviary", breviary, Lucene.Net.Documents.Field.Store.YES, Lucene.Net.Documents.Field.Index.NOT_ANALYZED)); + doc.Add(new Lucene.Net.Documents.Field("CreateTime", createTime, Lucene.Net.Documents.Field.Store.YES, Lucene.Net.Documents.Field.Index.NOT_ANALYZED)); // ANALYZED分词建索引 - doc.Add(new Field("FileName", fileName, Field.Store.YES, Field.Index.ANALYZED)); - doc.Add(new Field("FilePath", filePath, Field.Store.YES, Field.Index.ANALYZED)); - doc.Add(new Field("Content", content, Field.Store.NO, Field.Index.ANALYZED)); - - // GetIndexWriter().AddDocument(doc); - // 索引存在时更新,不存在时添加 - GetIndexWriter().UpdateDocument(new Term("FileMark", fileMark), doc); - - /*if (_finishCount % 1000 == 0 || _finishCount == _totalCount) - { - // 索引刷新 - GetIndexWriter().Optimize(10000); - }*/ - } - catch (Exception ex) - { - log.Error(filePath + " -> " + ex.Message, ex); - - Type ext = ex.GetType(); + doc.Add(new Lucene.Net.Documents.Field("FileName", fileName, Lucene.Net.Documents.Field.Store.YES, Lucene.Net.Documents.Field.Index.ANALYZED)); + doc.Add(new Lucene.Net.Documents.Field("FilePath", filePath, Lucene.Net.Documents.Field.Store.YES, Lucene.Net.Documents.Field.Index.ANALYZED)); + doc.Add(new Lucene.Net.Documents.Field("Content", content, Lucene.Net.Documents.Field.Store.NO, Lucene.Net.Documents.Field.Index.ANALYZED)); - if (ext == typeof(NullReferenceException) || ext == typeof(OutOfMemoryException)) - { - // 关闭并销毁索引写入器 - CloseIndexWriter(); - } - - // 手动GC - ManualGC(); - } - finally - { - // 完成数+1 - _finishCount++; + // 执行删除、添加逻辑 + AddDocument(filePath, doc); } + msg.Append(",索引:" + taskMark.ConsumeTime + "秒"); + } + else + { + msg.Append(",返回内容为空不创建索引。。。"); } - msg.Append(",索引:" + taskMark.ConsumeTime + "秒"); // 执行状态回调 - // taskInfo.Callback(msg.ToString(), CalcFinishRatio(_finishCount, taskInfo.TotalCount)); _callback(msg.ToString(), CalcFinishRatio(_finishCount, _totalCount)); log.Debug(msg); } - catch { } + catch (Exception ex) + { + log.Error(ex.Message, ex); + } finally { - // 标记当前任务完成,唤醒等待线程继续执行 + // 完成数量+1 + Interlocked.Increment(ref _finishCount); + + // 当前任务执行完成,唤醒等待线程继续执行 taskInfo.ResetEvent.SetOne(); } } + + /// + /// 添加文件索引Doc + /// + /// 文件路径 + /// 文件索引Doc + private static void AddDocument(string filePath, Lucene.Net.Documents.Document doc) + { + try + { + // 文件标记 + string fileMark = MD5Util.GetMD5Hash(filePath); + + _indexWriter.UpdateDocument(new Term("FileMark", fileMark), doc); + } + catch(Exception ex) + { + log.Error(filePath + " -> " + ex.Message + " => 重启索引写入器!", ex); + + + // 关闭索引写入器 + CloseIndexWriter(); + + // 创建索引写入器 + CreateIndexWriter(); + + log.Debug(filePath + " -> 重新执行添加操作"); + + AddDocument(filePath, doc); + } + } #endregion #region 完成比例计算器 diff --git a/TextLocator/Index/MutipleThreadResetEvent.cs b/TextLocator/Index/MutipleThreadResetEvent.cs index a395a443d26499b47fc1af8a2229be7db9ed8ea0..28560637d4ae1c4d75e0da97ecaf1a8ecbce2ae8 100644 --- a/TextLocator/Index/MutipleThreadResetEvent.cs +++ b/TextLocator/Index/MutipleThreadResetEvent.cs @@ -18,15 +18,15 @@ namespace TextLocator.Index /// /// 人工重置的事件 /// - private readonly ManualResetEvent done; + private readonly ManualResetEvent _event; /// /// 任务总数 /// - private readonly int total; + private readonly int _total; /// - /// 任务当前剩余数量 + /// 剩余数量 /// - private long current; + private volatile int _current; /// /// 构造函数 @@ -34,9 +34,9 @@ namespace TextLocator.Index /// 需要等待执行的线程总数 public MutipleThreadResetEvent(int total) { - this.total = total; - this.current = total; - this.done = new ManualResetEvent(false); + this._total = total; + this._current = total; + this._event = new ManualResetEvent(false); } /// @@ -45,10 +45,10 @@ namespace TextLocator.Index public void SetOne() { // Interlocked 原子操作类 ,此处将计数器减1 - if (Interlocked.Decrement(ref current) == 0) + if (Interlocked.Decrement(ref _current) == 0) { //当所以等待线程执行完毕时,唤醒等待的线程 - done.Set(); + _event.Set(); } } @@ -57,7 +57,7 @@ namespace TextLocator.Index /// public void WaitAll() { - done.WaitOne(); + _event.WaitOne(); } /// @@ -65,7 +65,7 @@ namespace TextLocator.Index /// public void Dispose() { - done.Dispose(); + ((IDisposable)_event).Dispose(); } } } diff --git a/TextLocator/MainWindow.xaml.cs b/TextLocator/MainWindow.xaml.cs index dedf870cad2e806e54c122f3e0fb655a4a4a8c70..5568a2e07eaa0c6bdb5778cae50fb86199c1564b 100644 --- a/TextLocator/MainWindow.xaml.cs +++ b/TextLocator/MainWindow.xaml.cs @@ -908,7 +908,7 @@ namespace TextLocator else { // 文件内容 - content = FileInfoServiceFactory.GetFileInfoService(fileInfo.FileType).GetFileContent(fileInfo.FilePath); + content = FileInfoServiceFactory.GetFileContent(fileInfo.FilePath); // 写入缓存 CacheUtil.Add(fileInfo.FilePath, content); @@ -985,7 +985,9 @@ namespace TextLocator private void MatchWords_Unchecked(object sender, RoutedEventArgs e) { BeforeSearch(); - } + } + + /// /// 优化按钮 @@ -1001,6 +1003,8 @@ namespace TextLocator } build = true; + ShowStatus("开始更新索引,请稍等..."); + BuildIndex(false); } @@ -1016,7 +1020,6 @@ namespace TextLocator Message.ShowWarning("MessageContainer", "索引构建中,不能重复执行!"); return; } - if (CheckIndexExist(false)) { var result = await MessageBoxR.ConfirmInContainer("DialogContaioner", "确定要重建索引嘛?时间可能比较久哦!", "提示"); @@ -1027,8 +1030,15 @@ namespace TextLocator } } + if (build) + { + Message.ShowWarning("MessageContainer", "索引构建中,请稍等。"); + return; + } build = true; + ShowStatus("开始重建索引,请稍等..."); + BuildIndex(true); } diff --git a/TextLocator/Properties/AssemblyInfo.cs b/TextLocator/Properties/AssemblyInfo.cs index 40dfbed18fd9bd85156ba64433e2b80384f90162..93deef0f125d064b40cc4164e484c5c23d3b2fe1 100644 --- a/TextLocator/Properties/AssemblyInfo.cs +++ b/TextLocator/Properties/AssemblyInfo.cs @@ -49,8 +49,8 @@ using System.Windows; //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 //通过使用 "*",如下所示: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.2.6")] -[assembly: AssemblyFileVersion("1.2.6.0")] +[assembly: AssemblyVersion("1.2.7")] +[assembly: AssemblyFileVersion("1.2.7.0")] // log4net [assembly: log4net.Config.XmlConfigurator(Watch = true)] \ No newline at end of file diff --git a/TextLocator/Service/ExcelFileService.cs b/TextLocator/Service/ExcelFileService.cs index 01418872a040a27bbdaf0893cf61ae78e4d4f115..d2e1d06aeddae45e6cd517ce5fdf13540832550b 100644 --- a/TextLocator/Service/ExcelFileService.cs +++ b/TextLocator/Service/ExcelFileService.cs @@ -26,111 +26,111 @@ namespace TextLocator.Service { try { - // =========== Spire.XLS =========== - // 创建Workbook对象 - using (Spire.Xls.Workbook workbook = new Spire.Xls.Workbook()) + // =========== NPIO =========== + // 文件流 + using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { - // 加载Excel文档 - workbook.LoadFromFile(filePath); - StringBuilder builder = new StringBuilder(); - if (workbook != null) + // 获取扩展名 + string extName = Path.GetExtension(filePath); + // 读取IWorkbook + IWorkbook readWorkbook = null; + switch (extName) { - WorksheetsCollection sheets = workbook.Worksheets; - if (sheets != null && sheets.Count > 0) + // 把xls写入workbook中 2003版本 + case ".xls": + readWorkbook = new HSSFWorkbook(fileStream); + break; + // 把xlsx 写入workbook中 2007版本 + case ".xlsx": + readWorkbook = new XSSFWorkbook(fileStream); + break; + default: + break; + } + + if (readWorkbook != null) + { + StringBuilder builder = new StringBuilder(); + // 获取表 + var sheetCount = readWorkbook.NumberOfSheets; + if (sheetCount > 0) { - // 获取工作表 - for (int i = 0; i < sheets.Count; i++) + for (int i = 0; i < sheetCount; i++) { - using (Spire.Xls.Worksheet sheet = sheets[i]) + // 得到sheet数据 + ISheet sheet = readWorkbook.GetSheetAt(i); + if (sheet != null) { - // 行 - for (int j = sheet.FirstRow; j < sheet.LastRow; j++) + // 获取行数 + var rowCount = sheet.LastRowNum; + // 解析行数据 + for (int j = 0; j <= rowCount; j++) { - using (Spire.Xls.CellRange row = sheet.Rows[j]) + // 得到row数据 + IRow row = sheet.GetRow(j); + if (row != null) { - // 列 - for (int k = 0; k < row.Columns.Length; k++) + // 解析列数据 + for (int k = 0; k < row.LastCellNum; k++) { - builder.Append(row.Columns[k].Value2.ToString() + " "); + // 得到cell数据 + ICell cell = row.GetCell(k); + // 获取某行某列对应的单元格数据 + builder.Append(cell + " "); } + // 换行 + builder.AppendLine(); } - builder.AppendLine(); } } } } + readWorkbook.Close(); + + content = builder.ToString(); } - content = builder.ToString(); } } catch (Exception spirex) { log.Error(filePath + " -> " + spirex.Message + " Spire.Xls解析错误,尝试NPIO", spirex); - // =========== NPIO =========== try { - // 文件流 - using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) + // =========== Spire.XLS =========== + // 创建Workbook对象 + using (Spire.Xls.Workbook workbook = new Spire.Xls.Workbook()) { - // 获取扩展名 - string extName = Path.GetExtension(filePath); - // 读取IWorkbook - IWorkbook readWorkbook = null; - switch (extName) + // 加载Excel文档 + workbook.LoadFromFile(filePath); + StringBuilder builder = new StringBuilder(); + if (workbook != null) { - // 把xls写入workbook中 2003版本 - case ".xls": - readWorkbook = new HSSFWorkbook(fileStream); - break; - // 把xlsx 写入workbook中 2007版本 - case ".xlsx": - readWorkbook = new XSSFWorkbook(fileStream); - break; - default: - break; - } - - if (readWorkbook != null) - { - StringBuilder builder = new StringBuilder(); - // 获取表 - var sheetCount = readWorkbook.NumberOfSheets; - if (sheetCount > 0) + WorksheetsCollection sheets = workbook.Worksheets; + if (sheets != null && sheets.Count > 0) { - for (int i = 0; i < sheetCount; i++) + // 获取工作表 + for (int i = 0; i < sheets.Count; i++) { - // 得到sheet数据 - ISheet sheet = readWorkbook.GetSheetAt(i); - if (sheet != null) + using (Spire.Xls.Worksheet sheet = sheets[i]) { - // 获取行数 - var rowCount = sheet.LastRowNum; - // 解析行数据 - for (int j = 0; j <= rowCount; j++) + // 行 + for (int j = sheet.FirstRow; j < sheet.LastRow; j++) { - // 得到row数据 - IRow row = sheet.GetRow(j); - if (row != null) + using (Spire.Xls.CellRange row = sheet.Rows[j]) { - // 解析列数据 - for (int k = 0; k < row.LastCellNum; k++) + // 列 + for (int k = 0; k < row.Columns.Length; k++) { - // 得到cell数据 - ICell cell = row.GetCell(k); - // 获取某行某列对应的单元格数据 - builder.Append(cell + " "); + builder.Append(row.Columns[k].Value2.ToString() + " "); } - // 换行 - builder.AppendLine(); } + builder.AppendLine(); } } } } - readWorkbook.Close(); - - content = builder.ToString(); } + content = builder.ToString(); } } catch (Exception ex) diff --git a/TextLocator/SettingWindow.xaml b/TextLocator/SettingWindow.xaml new file mode 100644 index 0000000000000000000000000000000000000000..22cafdcd53297095455cf7cc5e90139cd2ad73a3 --- /dev/null +++ b/TextLocator/SettingWindow.xaml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +