Browse Source

添加文件监控(灵活调整文件不存在的策略)

yuzhengyang 8 years ago
parent
commit
42b79923a6

+ 7 - 1
Fork.Net/Oreo.Plugins/Oreo.FileMan/Commons/R.cs

@@ -1,4 +1,5 @@
-using System;
+using Oreo.FileMan.Services;
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Reflection;
@@ -31,5 +32,10 @@ namespace Oreo.FileMan.Commons
             //public static string Settings = Paths.Root + "\\Settings.ini";//应用配置信息目录
             public static string Frisbee = Paths.App + "\\Frisbee.ini";
         }
+
+        public static class Services
+        {
+            public static FileBackupService FBS = new FileBackupService();
+        }
     }
 }

+ 13 - 1
Fork.Net/Oreo.Plugins/Oreo.FileMan/Models/BackupFiles.cs

@@ -8,9 +8,21 @@ namespace Oreo.FileMan.Models
     public class BackupFiles
     {
         public int Id { get; set; }
+        /// <summary>
+        /// 原路径
+        /// </summary>
         public string FullPath { get; set; }
+        /// <summary>
+        /// 备份路径
+        /// </summary>
         public string BackupFullPath { get; set; }
+        /// <summary>
+        /// 文件大小
+        /// </summary>
         public long Size { get; set; }
-        public string UpdateTime { get; set; }
+        /// <summary>
+        /// 备份时间
+        /// </summary>
+        public string BackupTime { get; set; }
     }
 }

+ 4 - 1
Fork.Net/Oreo.Plugins/Oreo.FileMan/Oreo.FileMan.csproj

@@ -124,6 +124,7 @@
     </Compile>
     <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Services\FileBackupService.cs" />
     <Compile Include="Views\MainForm.cs">
       <SubType>Form</SubType>
     </Compile>
@@ -161,6 +162,9 @@
     <EmbeddedResource Include="Views\MainForm.resx">
       <DependentUpon>MainForm.cs</DependentUpon>
     </EmbeddedResource>
+    <EmbeddedResource Include="Views\SettingsForm.resx">
+      <DependentUpon>SettingsForm.cs</DependentUpon>
+    </EmbeddedResource>
     <None Include="packages.config" />
     <None Include="Properties\app.manifest">
       <SubType>Designer</SubType>
@@ -180,7 +184,6 @@
   </ItemGroup>
   <ItemGroup>
     <Folder Include="Helpers\" />
-    <Folder Include="Services\" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\..\Fork.Net.SpeciallyTools\Y.FileQueryEngine\Y.FileQueryEngine.csproj">

+ 2 - 2
Fork.Net/Oreo.Plugins/Oreo.FileMan/Partials/FileBackupPartial.Designer.cs

@@ -56,7 +56,7 @@
             this.DgvPath.ReadOnly = true;
             this.DgvPath.RowHeadersVisible = false;
             this.DgvPath.RowTemplate.Height = 23;
-            this.DgvPath.Size = new System.Drawing.Size(214, 249);
+            this.DgvPath.Size = new System.Drawing.Size(214, 275);
             this.DgvPath.TabIndex = 0;
             this.DgvPath.CellDoubleClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.DgvPath_CellDoubleClick);
             // 
@@ -102,7 +102,7 @@
             this.DgvFile.ReadOnly = true;
             this.DgvFile.RowHeadersVisible = false;
             this.DgvFile.RowTemplate.Height = 23;
-            this.DgvFile.Size = new System.Drawing.Size(385, 249);
+            this.DgvFile.Size = new System.Drawing.Size(385, 275);
             this.DgvFile.TabIndex = 2;
             // 
             // DgvFileName

+ 11 - 96
Fork.Net/Oreo.Plugins/Oreo.FileMan/Partials/FileBackupPartial.cs

@@ -18,43 +18,25 @@ using Y.Utils.IOUtils.FileManUtils;
 using System.Windows.Threading;
 using System.Threading;
 using Y.Utils.DataUtils.DateTimeUtils;
+using Oreo.FileMan.Commons;
 
 namespace Oreo.FileMan.Partials
 {
     public partial class FileBackupPartial : UserControl
     {
-        FileWatcher Watcher = new FileWatcher();
-        string FileManBackup = @"G:\FileManBackup\";
-        List<BackupPaths> Paths = new List<BackupPaths>();
-        List<string> BackupFiles = new List<string>();
-        DispatcherTimer Timer = new DispatcherTimer();
-        int BACK_UP_INTERVAL = 5 * 1000;
-
         public FileBackupPartial()
         {
             InitializeComponent();
         }
         private void FileBackupPartial_Load(object sender, EventArgs e)
         {
-            Watcher.eventHandler += WatcherChangedEvent;
-            BackupFileTask();
-
-            //读取要备份的文件路径列表
-            Task.Factory.StartNew(() =>
+            if (ListTool.HasElements(R.Services.FBS.Paths))
             {
-                using (var db = new Muse())
+                foreach(var p in R.Services.FBS.Paths)
                 {
-                    Paths = db.GetAll<BackupPaths>(null, false).ToList();
-                    if (ListTool.HasElements(Paths))
-                    {
-                        foreach (var p in Paths)
-                        {
-                            Watcher.Add(p.Path, true);
-                            UIDgvPathAdd(DirTool.GetPathName(p.Path));
-                        }
-                    }
+                    UIDgvPathAdd(DirTool.GetPathName(p.Path));
                 }
-            });
+            } 
         }
 
         private void BtAddPath_Click(object sender, EventArgs e)
@@ -67,7 +49,7 @@ namespace Oreo.FileMan.Partials
                 string path = DirTool.Combine(selPath, "\\");//格式化选中的目录
                 string name = DirTool.GetPathName(selPath);//获取目录名称
 
-                List<BackupPaths> clashPath = Paths.Where(x => x.Path.Contains(path) || path.Contains(x.Path)).ToList();//查询冲突项
+                List<BackupPaths> clashPath = R.Services.FBS.Paths.Where(x => x.Path.Contains(path) || path.Contains(x.Path)).ToList();//查询冲突项
                 if (ListTool.HasElements(clashPath))
                 {
                     string cp = "";
@@ -88,8 +70,8 @@ namespace Oreo.FileMan.Partials
                                 BackupPaths bp = new BackupPaths() { Path = path, Alias = Guid.NewGuid().ToString() };
                                 if (db.Add(bp) > 0)
                                 {
-                                    Paths.Add(bp);//添加到列表
-                                    Watcher.Add(bp.Path, true);//添加到监听
+                                    R.Services.FBS.Paths.Add(bp);//添加到列表
+                                    R.Services.FBS.Watcher.AddPath(bp.Path);//添加到监听
                                     UIDgvPathAdd(name);//添加到列表UI
 
                                     long size = 0;//目录下的文件大小
@@ -115,14 +97,14 @@ namespace Oreo.FileMan.Partials
             if (DgvPath.CurrentRow != null)
             {
                 int row = DgvPath.CurrentRow.Index;
-                string path = Paths[row].Path;
+                string path = R.Services.FBS.Paths[row].Path;
                 if (row >= 0)
                 {
                     using (var db = new Muse())
                     {
                         BackupPaths bp = db.Get<BackupPaths>(x => x.Path == path, null);
                         if (bp != null) db.Del(bp, true);
-                        Paths.RemoveAt(row);
+                        R.Services.FBS.Paths.RemoveAt(row);
                     }
                     UIDgvPathDel(row);
                 }
@@ -132,7 +114,7 @@ namespace Oreo.FileMan.Partials
         {
             if (e.RowIndex >= 0)
             {
-                string path = Paths[e.RowIndex].Path;
+                string path = R.Services.FBS.Paths[e.RowIndex].Path;
                 UIEnableButton(false);
                 DgvFile.Rows.Clear();
                 Task.Factory.StartNew(() =>
@@ -149,74 +131,7 @@ namespace Oreo.FileMan.Partials
                 });
             }
         }
-        private void WatcherChangedEvent(object sender, FileWatcherEventArgs e)
-        {
-            if (Paths.Any(x => e.FullPath.Contains(x.Path)))
-            {
-                //变动的是文件且文件存在
-                if (FileTool.IsFile(e.FullPath))
-                {
-                    //添加到备份列表
-                    if (!BackupFiles.Contains(e.FullPath)) BackupFiles.Add(e.FullPath);
-                    UIDgvFileAdd(e.Name, e.FullPath, e.ChangeType.ToString());
-                }
-            }
-        }
-        private void BackupFileTask()
-        {
-            Task.Factory.StartNew(() =>
-            {
-                while (!IsDisposed)
-                {
-                    if (ListTool.HasElements(BackupFiles))
-                    {
-                        //获取要备份的文件列表并复制样本
-                        List<string> temp;
-                        lock (BackupFiles)
-                        {
-                            temp = BackupFiles;
-                            BackupFiles = new List<string>();
-                        }
 
-                        foreach (var t in temp)
-                        {
-                            if (File.Exists(t))
-                            {
-                                string filepath = DirTool.GetFilePath(t);
-                                BackupPaths path = Paths.FirstOrDefault(x => filepath.Contains(x.Path));
-                                if (path != null)
-                                {
-                                    string pathname = path.Path;
-                                    string pathalias = path.Alias;
-                                    string pathfile = t.Substring(pathname.Length, t.Length - pathname.Length);
-                                    string fileext = DateTimeConvert.CompactString(DateTime.Now);
-                                    string fullpath = DirTool.Combine(FileManBackup, pathalias, pathfile + "." + fileext);
-                                    try
-                                    {
-                                        if (DirTool.Create(DirTool.GetFilePath(fullpath)))
-                                        {
-                                            File.Copy(t, fullpath, true);
-                                            using (var db = new Muse())
-                                            {
-                                                db.Add(new BackupFiles()
-                                                {
-                                                    FullPath = t,
-                                                    BackupFullPath = fullpath,
-                                                    Size = FileTool.Size(t),
-                                                    UpdateTime = DateTimeConvert.StandardString(DateTime.Now),
-                                                });
-                                            }
-                                        }
-                                    }
-                                    catch (Exception e) { }
-                                }
-                            }
-                        }
-                    }
-                    Thread.Sleep(BACK_UP_INTERVAL);
-                }
-            });
-        }
 
         /// <summary>
         /// 停用或启用所有按钮

+ 10 - 4
Fork.Net/Oreo.Plugins/Oreo.FileMan/Program.cs

@@ -1,9 +1,11 @@
-using Oreo.FileMan.Views;
+using Oreo.FileMan.Commons;
+using Oreo.FileMan.Views;
 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Threading.Tasks;
 using System.Windows.Forms;
+using Y.Utils.AppUtils;
 
 namespace Oreo.FileMan
 {
@@ -15,9 +17,13 @@ namespace Oreo.FileMan
         [STAThread]
         static void Main()
         {
-            Application.EnableVisualStyles();
-            Application.SetCompatibleTextRenderingDefault(false);
-            Application.Run(new MainForm());
+            if (AppUnique.IsUnique("Oreo.FileMan"))
+            {
+                R.Services.FBS.Start();
+                Application.EnableVisualStyles();
+                Application.SetCompatibleTextRenderingDefault(false);
+                Application.Run(new MainForm());
+            }
         }
     }
 }

+ 172 - 0
Fork.Net/Oreo.Plugins/Oreo.FileMan/Services/FileBackupService.cs

@@ -0,0 +1,172 @@
+using Oreo.FileMan.DatabaseEngine;
+using Oreo.FileMan.Models;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Y.Utils.DataUtils.Collections;
+using Y.Utils.DataUtils.DateTimeUtils;
+using Y.Utils.IOUtils.FileManUtils;
+using Y.Utils.IOUtils.FileUtils;
+using Y.Utils.IOUtils.PathUtils;
+
+namespace Oreo.FileMan.Services
+{
+    public class FileBackupService
+    {
+        public FileWatcher Watcher = new FileWatcher(null);
+        public string FileManBackup = @"G:\FileManBackup\";
+        public List<BackupPaths> Paths = new List<BackupPaths>();
+
+        List<string> BackupFiles = new List<string>();
+        int BACK_UP_INTERVAL = 5 * 1000;
+        int BACK_UP_COUNT = 5;
+        bool IsStart = false;
+
+        public void Start()
+        {
+            if (!IsStart)
+            {
+                IsStart = true;
+
+                Watcher.eventHandler += WatcherChangedEvent;
+                Watcher.Start();//启动文件变动监听
+
+                Task.Factory.StartNew(() => { ReadBackupPaths(); });//读取备份文件夹列表
+                Task.Factory.StartNew(() => { BackupFileTask(); });//开始定时备份文件任务
+            }
+        }
+        public void Stop()
+        {
+            if (IsStart)
+            {
+                IsStart = false;
+            }
+        }
+        private void WatcherChangedEvent(object sender, FileWatcherEventArgs e)
+        {
+            if (Paths.Any(x => e.FullPath.Contains(x.Path)))
+            {
+                //变动的是文件且文件存在
+                if (FileTool.IsFile(e.FullPath))
+                {
+                    //添加到备份列表
+                    if (!BackupFiles.Contains(e.FullPath)) BackupFiles.Add(e.FullPath);
+                    //UIDgvFileAdd(e.Name, e.FullPath, e.ChangeType.ToString());
+                }
+            }
+        }
+        private void BackupFileTask()
+        {
+            while (IsStart)
+            {
+                if (ListTool.HasElements(BackupFiles))
+                {
+                    //获取要备份的文件列表并复制样本
+                    List<string> temp;
+                    lock (BackupFiles)
+                    {
+                        temp = BackupFiles;
+                        BackupFiles = new List<string>();
+                    }
+
+                    foreach (var t in temp)
+                    {
+                        if (File.Exists(t))
+                        {
+                            string filepath = DirTool.GetFilePath(t);
+                            BackupPaths path = Paths.FirstOrDefault(x => filepath.Contains(x.Path));
+                            if (path != null)
+                            {
+                                string pathname = path.Path;
+                                string pathalias = path.Alias;
+                                string pathfile = t.Substring(pathname.Length, t.Length - pathname.Length);
+                                string fileext = DateTimeConvert.CompactString(DateTime.Now);
+                                string fullpath = DirTool.Combine(FileManBackup, pathalias, pathfile + "." + fileext);
+
+                                //删除冗余
+                                DeleteExcess(t);
+                                //备份文件
+                                BackupFile(t, fullpath);
+                            }
+                        }
+                    }
+                }
+                Thread.Sleep(BACK_UP_INTERVAL);
+            }
+        }
+
+        /// <summary>
+        /// 读取备份文件夹列表
+        /// </summary>
+        private void ReadBackupPaths()
+        {
+            //读取要备份的文件路径列表
+            using (var db = new Muse())
+            {
+                Paths = db.GetAll<BackupPaths>(null, false).ToList();
+                if (ListTool.HasElements(Paths))
+                {
+                    foreach (var p in Paths)
+                    {
+                        Watcher.AddPath(p.Path);
+                    }
+                }
+            }
+        }
+        /// <summary>
+        /// 删除超过备份最大次数的项
+        /// </summary>
+        private void DeleteExcess(string path)
+        {
+            using (var db = new Muse())
+            {
+                int count = db.Do<BackupFiles>().Count(x => x.FullPath == path);
+                if (count >= BACK_UP_COUNT)
+                {
+                    var fs = db.Gets<BackupFiles>(x => x.FullPath == path, null).OrderBy(x => x.Id).ToList();
+                    if (ListTool.HasElements(fs))
+                    {
+                        for (int i = 0; i <= count - BACK_UP_COUNT; i++)
+                        {
+                            try
+                            {
+                                File.Delete(fs[i].BackupFullPath);
+                                db.Del(fs[i], true);
+                            }
+                            catch (Exception e) { }
+                        }
+                    }
+                }
+            }
+        }
+        /// <summary>
+        /// 备份文件
+        /// </summary>
+        /// <param name="path"></param>
+        /// <param name="newpath"></param>
+        private void BackupFile(string path, string newpath)
+        {
+            using (var db = new Muse())
+            {
+                try
+                {
+                    if (DirTool.Create(DirTool.GetFilePath(newpath)))
+                    {
+                        File.Copy(path, newpath, true);
+                        db.Add(new BackupFiles()
+                        {
+                            FullPath = path,
+                            BackupFullPath = newpath,
+                            Size = FileTool.Size(path),
+                            BackupTime = DateTimeConvert.StandardString(DateTime.Now),
+                        });
+                    }
+                }
+                catch (Exception e) { }
+            }
+        }
+    }
+}

+ 57 - 1
Fork.Net/Oreo.Plugins/Oreo.FileMan/Views/SettingsForm.Designer.cs

@@ -28,11 +28,67 @@
         /// </summary>
         private void InitializeComponent()
         {
-            this.components = new System.ComponentModel.Container();
+            this.textBox1 = new System.Windows.Forms.TextBox();
+            this.button1 = new System.Windows.Forms.Button();
+            this.label1 = new System.Windows.Forms.Label();
+            this.label2 = new System.Windows.Forms.Label();
+            this.SuspendLayout();
+            // 
+            // textBox1
+            // 
+            this.textBox1.Location = new System.Drawing.Point(91, 90);
+            this.textBox1.Name = "textBox1";
+            this.textBox1.Size = new System.Drawing.Size(100, 21);
+            this.textBox1.TabIndex = 4;
+            // 
+            // button1
+            // 
+            this.button1.Location = new System.Drawing.Point(214, 90);
+            this.button1.Name = "button1";
+            this.button1.Size = new System.Drawing.Size(75, 23);
+            this.button1.TabIndex = 5;
+            this.button1.Text = "button1";
+            this.button1.UseVisualStyleBackColor = true;
+            // 
+            // label1
+            // 
+            this.label1.AutoSize = true;
+            this.label1.Location = new System.Drawing.Point(24, 90);
+            this.label1.Name = "label1";
+            this.label1.Size = new System.Drawing.Size(41, 12);
+            this.label1.TabIndex = 6;
+            this.label1.Text = "label1";
+            // 
+            // label2
+            // 
+            this.label2.AutoSize = true;
+            this.label2.Location = new System.Drawing.Point(26, 133);
+            this.label2.Name = "label2";
+            this.label2.Size = new System.Drawing.Size(41, 12);
+            this.label2.TabIndex = 7;
+            this.label2.Text = "label2";
+            // 
+            // SettingsForm
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.ClientSize = new System.Drawing.Size(340, 274);
+            this.Controls.Add(this.label2);
+            this.Controls.Add(this.label1);
+            this.Controls.Add(this.button1);
+            this.Controls.Add(this.textBox1);
+            this.Name = "SettingsForm";
             this.Text = "SettingsForm";
+            this.ResumeLayout(false);
+            this.PerformLayout();
+
         }
 
         #endregion
+
+        private System.Windows.Forms.TextBox textBox1;
+        private System.Windows.Forms.Button button1;
+        private System.Windows.Forms.Label label1;
+        private System.Windows.Forms.Label label2;
     }
 }

+ 2 - 1
Fork.Net/Oreo.Plugins/Oreo.FileMan/Views/SettingsForm.cs

@@ -7,10 +7,11 @@ using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using System.Windows.Forms;
+using Y.Skin.YoForm.NoTitle;
 
 namespace Oreo.FileMan.Views
 {
-    public partial class SettingsForm : Form
+    public partial class SettingsForm : NoTitleForm
     {
         public SettingsForm()
         {

+ 120 - 0
Fork.Net/Oreo.Plugins/Oreo.FileMan/Views/SettingsForm.resx

@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

+ 75 - 82
Fork.Net/Y.Utils/IOUtils/FileManUtils/FileWatcher.cs

@@ -7,10 +7,13 @@
 //************************************************************************
 
 using System;
+using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
 using Y.Utils.DataUtils.Collections;
 
 namespace Y.Utils.IOUtils.FileManUtils
@@ -18,7 +21,7 @@ namespace Y.Utils.IOUtils.FileManUtils
     /// <summary>
     /// 文件更改通知
     /// </summary>
-    public class FileWatcher : IDisposable
+    public class FileWatcher
     {
         /// <summary>
         /// 接受文件监控信息的事件委托
@@ -31,70 +34,50 @@ namespace Y.Utils.IOUtils.FileManUtils
         /// </summary>
         public FileWatcherEventHandler eventHandler;
 
-        private bool _IsStart = false, _IsDisposed = false;
-        private List<FileSystemWatcher> Watchers = new List<FileSystemWatcher>();
+        private int Interval = 10 * 1000;
+        private bool _IsWatching = false;
+        private ConcurrentDictionary<string, FileSystemWatcher> Watchers = new ConcurrentDictionary<string, FileSystemWatcher>();
 
         /// <summary>
-        /// 当前运行状态
+        /// 文件更改监控已启动
         /// </summary>
-        public bool IsStart { get { return _IsStart; } }
+        public bool IsWatching { get { return _IsWatching; } }
 
-
-        public FileWatcher()
-        {
-            //DriveInfo[] drives = DriveInfo.GetDrives().Where(x => x.IsReady && (x.DriveType == DriveType.Fixed || x.DriveType == DriveType.Removable)).ToArray();
-            //if (ListTool.HasElements(drives))
-            //{
-            //    foreach (var d in drives)
-            //    {
-            //        //if (d.Name.Contains("C")) continue;
-            //        FileSystemWatcher fsw = new FileSystemWatcher(d.Name);
-            //        fsw.Created += CreatedEvent;//创建文件或目录
-            //        fsw.Changed += ChangedEvent;//更改文件或目录
-            //        fsw.Deleted += DeletedEvent;//删除文件或目录
-            //        fsw.Renamed += RenamedEvent;//重命名文件或目录
-            //        fsw.Error += ErrorEvent;
-            //        fsw.IncludeSubdirectories = true;
-            //        fsw.NotifyFilter = (NotifyFilters)383;
-            //        Watchers.Add(fsw);
-            //    }
-            //}
-        }
+        /// <summary>
+        /// 创建文件监控类
+        /// </summary>
+        /// <param name="paths"></param>
         public FileWatcher(string[] paths)
         {
             if (ListTool.HasElements(paths))
             {
                 foreach (var p in paths)
                 {
-                    Add(p);
+                    if (Directory.Exists(p) && !Watchers.ContainsKey(p))
+                        Watchers.TryAdd(p, null);
                 }
             }
         }
 
-        public void Add(string path, bool start = false)
+        public bool AddPath(string path)
         {
-            FileSystemWatcher fsw = new FileSystemWatcher(path);
-            fsw.Created += CreatedEvent;//创建文件或目录
-            fsw.Changed += ChangedEvent;//更改文件或目录
-            fsw.Deleted += DeletedEvent;//删除文件或目录
-            fsw.Renamed += RenamedEvent;//重命名文件或目录
-            fsw.Error += ErrorEvent;
-            fsw.IncludeSubdirectories = true;
-            fsw.NotifyFilter = (NotifyFilters)383;
-            if (start) fsw.EnableRaisingEvents = start;
-            Watchers.Add(fsw);
+            if (Directory.Exists(path) && !Watchers.ContainsKey(path))
+                return Watchers.TryAdd(path, null);
+            return false;
         }
-        public void Remove(string path)
+        public bool DelPath(string path)
         {
-            for (int i = Watchers.Count - 1; i >= 0; i--)
+            if (Watchers.ContainsKey(path))
             {
-                if (Watchers[i].Path == path)
+                FileSystemWatcher temp;
+                if (Watchers.TryRemove(path, out temp) && temp != null)
                 {
-                    Watchers[i].EnableRaisingEvents = false;
-                    Watchers[i].Dispose();
-                    Watchers.RemoveAt(i);
+                    temp.EnableRaisingEvents = false;
+                    temp.Dispose();
+                    return true;
                 }
             }
+            return false;
         }
 
         /// <summary>
@@ -102,16 +85,37 @@ namespace Y.Utils.IOUtils.FileManUtils
         /// </summary>
         public void Start()
         {
-            if (!_IsDisposed)
+            if (!_IsWatching)
             {
-                _IsStart = true;
-                if (ListTool.HasElements(Watchers))
+                _IsWatching = true;
+                Task.Factory.StartNew(() =>
                 {
-                    foreach (var w in Watchers)
+                    while (_IsWatching)
                     {
-                        w.EnableRaisingEvents = true;
+                        foreach (var item in Watchers)
+                        {
+                            if (item.Value == null)
+                            {
+                                if (Directory.Exists(item.Key))
+                                {
+                                    Watchers.TryUpdate(item.Key, CreateWatcher(item.Key), null);
+                                }
+                            }
+                            else
+                            {
+                                if (!Directory.Exists(item.Key))
+                                {
+                                    item.Value.EnableRaisingEvents = false;
+                                    item.Value.Dispose();
+                                    Watchers.TryUpdate(item.Key, null, item.Value);
+                                }
+                            }
+                        }
+
+                        Thread.Sleep(Interval);
                     }
-                }
+                    _IsWatching = false;
+                });
             }
         }
         /// <summary>
@@ -119,29 +123,36 @@ namespace Y.Utils.IOUtils.FileManUtils
         /// </summary>
         public void Stop()
         {
-            if (!_IsDisposed)
+            _IsWatching = false;
+            foreach (var item in Watchers.Keys)
             {
-                _IsStart = false;
-                if (ListTool.HasElements(Watchers))
+                if (Watchers.ContainsKey(item))
                 {
-                    foreach (var w in Watchers)
+                    if (Watchers[item] != null) Watchers[item].EnableRaisingEvents = false;
+
+                    FileSystemWatcher temp;
+                    if (Watchers.TryRemove(item, out temp) && temp != null)
                     {
-                        w.EnableRaisingEvents = false;
+                        temp.EnableRaisingEvents = false;
+                        temp.Dispose();
                     }
                 }
             }
         }
 
-
-
-
-        private void DriveMonitor()
+        private FileSystemWatcher CreateWatcher(string path)
         {
-            //监测磁盘的插入拔出
-
+            FileSystemWatcher fsw = new FileSystemWatcher(path);
+            fsw.Created += CreatedEvent;//创建文件或目录
+            fsw.Changed += ChangedEvent;//更改文件或目录
+            fsw.Deleted += DeletedEvent;//删除文件或目录
+            fsw.Renamed += RenamedEvent;//重命名文件或目录
+            fsw.Error += ErrorEvent;
+            fsw.IncludeSubdirectories = true;
+            fsw.NotifyFilter = (NotifyFilters)383;
+            fsw.EnableRaisingEvents = true;
+            return fsw;
         }
-
-
         private void CreatedEvent(object sender, FileSystemEventArgs e)
         {
             eventHandler?.Invoke(sender, new FileWatcherEventArgs(e.ChangeType, e.FullPath, Path.GetFileName(e.FullPath), null, null));
@@ -159,24 +170,6 @@ namespace Y.Utils.IOUtils.FileManUtils
             eventHandler?.Invoke(sender, new FileWatcherEventArgs(e.ChangeType, e.FullPath, Path.GetFileName(e.FullPath), e.OldFullPath, e.OldName));
         }
         private void ErrorEvent(object sender, ErrorEventArgs e)
-        {
-        }
-
-        public void Dispose()
-        {
-            if (!_IsDisposed)
-            {
-                _IsStart = false;
-                _IsDisposed = true;
-                if (ListTool.HasElements(Watchers))
-                {
-                    foreach (var w in Watchers)
-                    {
-                        w.EnableRaisingEvents = false;
-                        w.Dispose();
-                    }
-                }
-            }
-        }
+        { }
     }
 }