diff --git a/TextLocator/App.xaml.cs b/TextLocator/App.xaml.cs
index d2945e04cbce1f417a4a7e12832bb9bb253dee04..503ed0cec7799776123cfc2b398a83394f9eb686 100644
--- a/TextLocator/App.xaml.cs
+++ b/TextLocator/App.xaml.cs
@@ -35,7 +35,7 @@ namespace TextLocator
// HTML或XML服务
FileInfoServiceFactory.Register(FileType.HTML和XML类型, new XmlFileService());
// 常用图片服务
- FileInfoServiceFactory.Register(FileType.常用图片, new DevelopFileService());
+ FileInfoServiceFactory.Register(FileType.常用图片, new ImageFileService());
// 程序员服务
FileInfoServiceFactory.Register(FileType.代码文件, new DevelopFileService());
// 纯文本服务
diff --git a/TextLocator/Index/LuceneIndexCore.cs b/TextLocator/Index/LuceneIndexCore.cs
index 24d438c31a41eb502f4dec09c3b8f55e47314e15..b4ba243eeeceda2987daeb033254f03dab467696 100644
--- a/TextLocator/Index/LuceneIndexCore.cs
+++ b/TextLocator/Index/LuceneIndexCore.cs
@@ -8,6 +8,8 @@ using System.Threading;
using TextLocator.Core;
using TextLocator.Enums;
using TextLocator.Factory;
+using TextLocator.Index;
+using TextLocator.Service;
using TextLocator.Util;
namespace TextLocator.Index
@@ -23,13 +25,23 @@ namespace TextLocator.Index
/// 状态回调委托
///
///
- public delegate void StatusCallback(string status);
+ public delegate void Callback(string status);
+
+ ///
+ /// 锁
+ ///
+ private static object locker = new object();
+
+ ///
+ /// 已完成数量
+ ///
+ private static volatile int finishCount = 0;
///
/// 创建索引
///
/// 获得的文档包
- public static void CreateIndex(List filePaths, bool rebuild, StatusCallback callback)
+ public static void CreateIndex(List filePaths, bool rebuild, Callback callback)
{
// 判断是创建索引还是增量索引(如果索引目录不存在,重建)
bool create = !Directory.Exists(AppConst.APP_INDEX_DIR);
@@ -40,26 +52,65 @@ namespace TextLocator.Index
}
// 索引写入初始化(FSDirectory表示索引存放在硬盘上,RAMDirectory表示放在内存上)
- Lucene.Net.Index.IndexWriter writer = new Lucene.Net.Index.IndexWriter(AppConst.INDEX_DIRECTORY, AppConst.INDEX_ANALYZER, create, Lucene.Net.Index.IndexWriter.MaxFieldLength.UNLIMITED);
+ Lucene.Net.Index.IndexWriter indexWriter = new Lucene.Net.Index.IndexWriter(AppConst.INDEX_DIRECTORY, AppConst.INDEX_ANALYZER, create, Lucene.Net.Index.IndexWriter.MaxFieldLength.UNLIMITED);
// 文件总数
int count = filePaths.Count();
- // 遍历读取文件,并创建索引
- for (int i = 0; i < count; i++)
+ using (var countDown = new MutipleThreadResetEvent(count))
{
- // 文件路径
- string filePath = filePaths[i];
+ // 设置线程最大数量
+ ThreadPool.SetMaxThreads(24, 48);
+ // 遍历读取文件,并创建索引
+ for (int i = 0; i < count; i++)
+ {
+ // 加入线程池
+ ThreadPool.QueueUserWorkItem(new WaitCallback(CreateIndexTask), new TaskInfo() {
+ TotalCount = count,
+ FilePath = filePaths[i],
+ Create = create,
+ IndexWriter = indexWriter,
+ Callback = callback,
+ ResetEvent = countDown
+ });
+ }
+
+ // 等待所有线程结束
+ countDown.WaitAll();
+ countDown.Dispose();
+ }
+ try
+ {
+ indexWriter.Dispose();
+ }
+ catch (Exception ex)
+ {
+ log.Error(ex.Message, ex);
+ }
+ }
+
+ ///
+ /// 创建索引任务方法
+ ///
+ ///
+ private static void CreateIndexTask(object obj)
+ {
+ TaskInfo taskInfo = obj as TaskInfo;
+ try
+ {
+ string filePath = taskInfo.FilePath;
+ bool create = taskInfo.Create;
+ Lucene.Net.Index.IndexWriter indexWriter = taskInfo.IndexWriter;
// 临时文件跳过
- if (filePath.IndexOf("~$") >0)
+ if (filePath.IndexOf("~$") > 0)
{
- continue;
+ return;
}
// 非重建 && 文件已经被索引过
if (!create && !string.IsNullOrEmpty(AppUtil.ReadIni("FileIndex", filePath, "")))
{
- continue;
+ return;
}
// 写入
@@ -83,57 +134,78 @@ namespace TextLocator.Index
// 根据文件路径获取文件类型(自定义文件类型分类)
FileType fileType = FileTypeUtil.GetFileType(filePath);
- // 文件内容
- string content = FileInfoServiceFactory.GetFileInfoService(fileType)
- .GetFileContent(filePath);
-
- // 缩略信息
- string breviary = new Regex(" |\r|\n|\\s").Replace(content, "");
- if (breviary.Length > 150)
+ lock (locker)
{
- breviary = breviary.Substring(0, 150) + "...";
+ IFileInfoService fileInfoService = FileInfoServiceFactory.GetFileInfoService(fileType);
+
+ // 文件内容
+ string content = fileInfoService.GetFileContent(filePath);
+
+ // 缩略信息
+ string breviary = new Regex(" |\r|\n|\\s").Replace(content, "");
+ if (breviary.Length > 150)
+ {
+ breviary = breviary.Substring(0, 150) + "...";
+ }
+
+ // 当索引文件中含有与filemark相等的field值时,会先删除再添加,以防出现重复
+ indexWriter.DeleteDocuments(new Lucene.Net.Index.Term("FileMark", fileMark));
+
+ Lucene.Net.Documents.Document doc = new Lucene.Net.Documents.Document();
+ // 不分词建索引
+ 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 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));
+
+ indexWriter.AddDocument(doc);
+ // 优化索引
+ indexWriter.Optimize();
+
+ finishCount++;
}
- // 当索引文件中含有与filemark相等的field值时,会先删除再添加,以防出现重复
- writer.DeleteDocuments(new Lucene.Net.Index.Term("FileMark", fileMark));
-
- Lucene.Net.Documents.Document doc = new Lucene.Net.Documents.Document();
- // 不分词建索引
- 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 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));
-
- writer.AddDocument(doc);
- // 优化索引
- writer.Optimize();
-
- string msg = "创建索引:(" + i + " / " + count + ") => 文件:" + filePath + ",耗时:" + (DateTime.Now - beginMark).TotalSeconds + "秒";
+ string msg = "索引:[" + finishCount + " / " + taskInfo.TotalCount + "] => 文件:" + filePath + ",耗时:" + (DateTime.Now - beginMark).TotalSeconds + "秒";
// 执行状态回调
- callback(msg);
-
- log.Debug(msg);
-
- // 手动GC
- GC.Collect();
- GC.WaitForPendingFinalizers();
- }
+ taskInfo.Callback(msg);
- try
- {
- writer.Dispose();
+ log.Debug(msg);
}
catch (Exception ex)
{
log.Error(ex.Message, ex);
}
+ finally
+ {
+ // 手动GC
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+
+ try
+ {
+ taskInfo.ResetEvent.SetOne();
+ } catch { }
+ }
+ }
+
+ ///
+ /// 任务信息
+ ///
+ 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 LuceneIndexCore.Callback Callback { get; set; }
+ public MutipleThreadResetEvent ResetEvent { get; set; }
}
}
}
diff --git a/TextLocator/Index/MutipleThreadResetEvent.cs b/TextLocator/Index/MutipleThreadResetEvent.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7da4c27e9e75af8ff3ff647934213f2f01eefa0f
--- /dev/null
+++ b/TextLocator/Index/MutipleThreadResetEvent.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace TextLocator.Index
+{
+ ///
+ /// 多线程重置事件
+ ///
+ public class MutipleThreadResetEvent : IDisposable
+ {
+ private readonly ManualResetEvent done;
+ private readonly int total;
+ private long current;
+
+ ///
+ /// 构造函数
+ ///
+ /// 需要等待执行的线程总数
+ public MutipleThreadResetEvent(int total)
+ {
+ this.total = total;
+ current = total;
+ done = new ManualResetEvent(false);
+ }
+
+ ///
+ /// 唤醒一个等待的线程
+ ///
+ public void SetOne()
+ {
+ // Interlocked 原子操作类 ,此处将计数器减1
+ if (Interlocked.Decrement(ref current) == 0)
+ {
+ //当所以等待线程执行完毕时,唤醒等待的线程
+ done.Set();
+ }
+ }
+
+ ///
+ /// 等待所以线程执行完毕
+ ///
+ public void WaitAll()
+ {
+ done.WaitOne();
+ }
+
+ ///
+ /// 释放对象占用的空间
+ ///
+ public void Dispose()
+ {
+ ((IDisposable)done).Dispose();
+ }
+ }
+}
diff --git a/TextLocator/MainWindow.xaml.cs b/TextLocator/MainWindow.xaml.cs
index ac433cbbe0dcfefa32f459b07ef7abd57c663225..e856dde8d4717e9e1480a55387d2ad84fd5c501b 100644
--- a/TextLocator/MainWindow.xaml.cs
+++ b/TextLocator/MainWindow.xaml.cs
@@ -154,8 +154,15 @@ namespace TextLocator
LuceneIndexCore.CreateIndex(filePaths, rebuild, ShowStatus);
}
+ string msg = "索引执行结束,共用时:" + (DateTime.Now - beginMark).TotalSeconds + "秒";
+
// 显示状态
- ShowStatus("索引执行结束,共用时:" + (DateTime.Now - beginMark).TotalSeconds + "秒");
+ ShowStatus(msg);
+
+ this.Dispatcher.BeginInvoke(new Action(() =>
+ {
+ Message.ShowSuccess("MessageContainer", msg);
+ }));
// 构建结束
build = false;
@@ -181,8 +188,8 @@ namespace TextLocator
private void Search(List keywords, string fileTypeFilter)
{
string text = "";
- foreach(string kw in keywords) {
- text += kw + ",";
+ foreach(string keyword in keywords) {
+ text += keyword + ",";
}
text = text.Substring(0, text.Length - 1);
log.Debug("关键词:(" + text + "), 文件类型:" + fileTypeFilter);
@@ -304,7 +311,7 @@ namespace TextLocator
resultNum++;
}
- string message = "检索完成!共检索到" + resultNum + "个符合条件的结果(只显示前" + num + "条)。耗时:" + (DateTime.Now - beginMark).TotalSeconds + "秒";
+ string message = "检索完成!共检索到" + resultNum + "个符合条件的结果(只显示前" + num + "条)。耗时:" + (DateTime.Now - beginMark).TotalSeconds + "秒。";
Message.ShowSuccess("MessageContainer", message);
diff --git a/TextLocator/Properties/AssemblyInfo.cs b/TextLocator/Properties/AssemblyInfo.cs
index ebce5a442bd3077fa44346d726db5e04c1bdbceb..61c5dc01a4a674b467e0743105f39ff088092739 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.0")]
-[assembly: AssemblyFileVersion("1.0.0.5")]
+[assembly: AssemblyFileVersion("1.0.0.6")]
// log4net
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
\ No newline at end of file
diff --git a/TextLocator/Resource/ext/code.png b/TextLocator/Resource/ext/code.png
index 7a187d851e02ee604253b11d58c97c6fd128683c..6c78e441ad7330788c836905db9a1c3475f22da0 100644
Binary files a/TextLocator/Resource/ext/code.png and b/TextLocator/Resource/ext/code.png differ
diff --git a/TextLocator/Resource/ext/jpg.png b/TextLocator/Resource/ext/jpg.png
index 418dd44f992b15be62b61b6fd2befec40b70271c..65fde8f648a39aa66235c5515355baab96bc0a0f 100644
Binary files a/TextLocator/Resource/ext/jpg.png and b/TextLocator/Resource/ext/jpg.png differ
diff --git a/TextLocator/TextLocator.csproj b/TextLocator/TextLocator.csproj
index fa3ae14080d1c53af6d51fc1eb353bc12a0230f1..ad3b88bfe80880bcbb26f46548ce1369af417c41 100644
--- a/TextLocator/TextLocator.csproj
+++ b/TextLocator/TextLocator.csproj
@@ -169,6 +169,7 @@
FolderWindow.xaml
+