using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml; using System.IO; using System.ComponentModel; using System.Collections.ObjectModel; namespace OBJ_FileBus { public class FileElement : INotifyPropertyChanged { public override string ToString() { string s=""; if (FileAttr == FileAttributes.Directory) s += "+" + Name + "+"; else s += "[" + Name + "]"; s += ","; s += LastWriteTime.ToShortTimeString(); s += ","; s += DownloadSize.ToString(); return s; } private string name = ""; /// <summary> /// 文件名 /// </summary> public string Name { get { return name; } set { if (name != value) { name = value; NotifyPropertyChanged("Name"); } } } private FileAttributes fileAttributes = FileAttributes.Normal; /// <summary> /// 文件属性,文件Normal or 文件夹Directory /// </summary> public FileAttributes FileAttr { get { return fileAttributes; } set { if (fileAttributes != value) { fileAttributes = value; NotifyPropertyChanged("FileAttr"); } } } private DateTime lastWriteTime = DateTime.Now; /// <summary> /// 最后修改时间 /// </summary> public DateTime LastWriteTime { get { return lastWriteTime; } set { if (lastWriteTime != value) { lastWriteTime = value; NotifyPropertyChanged("LastWriteTime"); BeChanged = true; } } } private DateTime createTime = DateTime.MinValue; /// <summary> /// 创建时间 /// </summary> public DateTime CreateTime { get { return createTime; } set { if (createTime != value) { createTime = value; NotifyPropertyChanged("CreateTime"); BeChanged = true; } } } private int size; public int Size { get { return size; } set { if (size != value) { size = value; NotifyPropertyChanged("Size"); BeChanged = true; } } } private bool update = false; /// <summary> /// 需要从服务器下载文件 /// </summary> public bool Update { get { return update; } set { if (update != value) { update = value; NotifyPropertyChanged("Update"); BeChanged = true; } } } private int download_size = 0; /// <summary> /// 已经下载了的大小 /// </summary> public int DownloadSize { get { return download_size; } set { if (download_size != value) { download_size = value; NotifyPropertyChanged("DownloadSize"); } } } //public List<FileElement> child; public ObservableCollection<FileElement> child; public FileElement parent; private bool beChanged = false; public bool BeChanged { get { return beChanged; } set { if (beChanged != value) { beChanged = value; if (beChanged) { if (parent != null) parent.BeChanged = true; } else { if (child != null) { foreach (FileElement f in child) f.BeChanged = false; } } NotifyPropertyChanged("BeChanged"); } } } public event EventHandler OnChanged;//TODO, 当数据发生变化时,调用 public class FileElementEventArgs : EventArgs { public string Path;//更新路径 } /// <summary> /// 总路径,不断向parent 查询 /// </summary> public string FullName { get { if (parent != null) { string name = parent.FullName; if (name == @"\") { return @"\" + Name; } else { return parent.FullName + @"\" + Name; } } else { return Name; } } } #region Load Save /// <summary> /// 从xmlnode 格式中提取 单层 FileElement 结构 加载到当前的 FileElement /// </summary> /// <param name="xmlNode"></param> /// <returns></returns> private bool Load(XmlNode xmlNode) { FileAttr = (FileAttributes)Enum.Parse(typeof(FileAttributes), xmlNode.Name); Name = xmlNode.Attributes["name"].Value; if (xmlNode.Attributes.GetNamedItem("ctime") != null) CreateTime = DateTime.Parse(xmlNode.Attributes["ctime"].Value); LastWriteTime = DateTime.Parse(xmlNode.Attributes["mtime"].Value); if (xmlNode.Attributes.GetNamedItem("size") != null) Size = int.Parse(xmlNode.Attributes["size"].Value); if (xmlNode.Attributes.GetNamedItem("update") != null) { Update = bool.Parse(xmlNode.Attributes["update"].Value); if (Update == false) DownloadSize = Size; } if (FileAttr == FileAttributes.Directory) { child = new ObservableCollection<FileElement>(); foreach (XmlNode xn in xmlNode.ChildNodes) { FileElement element = new FileElement(); element.Load(xn); AddChild(element); } } return true; } /// <summary> /// 保存 到 xml, level <= 1, 只保存本层, > 1, 连子层都保存 /// </summary> /// <param name="xmlDoc"></param> /// <returns></returns> private XmlNode Save(XmlDocument xmlDoc,int level) { XmlElement xmlElement = xmlDoc.CreateElement(FileAttr.ToString()); xmlElement.SetAttribute("name", Name); xmlElement.SetAttribute("ctime", Converter.DateTimeToString(CreateTime)); xmlElement.SetAttribute("mtime", Converter.DateTimeToString(LastWriteTime)); xmlElement.SetAttribute("size", Size.ToString()); xmlElement.SetAttribute("update", Update.ToString()); if (level > 1) { if (child != null) { foreach (FileElement fe in child) { xmlElement.AppendChild(fe.Save(xmlDoc,level)); } } } return xmlElement; } /// <summary> /// 被 FileBus.Client 调用, 用于加载 Gage1 的 xxx.fileinfo.xml /// 加载 xml 文件,会自动填充本项 及 子项 /// </summary> /// <param name="path"></param> /// <returns></returns> public bool Load(string path) { XmlDocument xmlDoc = new XmlDocument(); try { xmlDoc.Load(path); } catch { return false; } return Load(xmlDoc.DocumentElement); } /// <summary> /// 被 FileBus.Client 调用 /// 以当前项 与 子项 保存为 xml 文件 /// </summary> /// <param name="path"></param> public void Save(string path) { XmlDocument xmlDoc = new XmlDocument(); XmlNode node = Save(xmlDoc, 2); xmlDoc.AppendChild(node); xmlDoc.Save(path); } #endregion /// <summary> /// 添加单个子项 /// </summary> /// <param name="fElement"></param> private void AddChild(FileElement fElement) { child.Add(fElement); fElement.parent = this; BeChanged = true; } /// <summary> /// 在指定路径创建 子 FileElement /// </summary> /// <param name="XPath"></param> /// <param name="fa"></param> /// <returns></returns> private FileElement CreateNode(string XPath, FileAttributes fa) { string[] parent_path = XPath.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries); if (parent_path.Length == 0)//根目录为 @"\" { return this; } FileElement fe = this; foreach(string name in parent_path) { FileElement parent = fe; var fel = from _fe in parent.child where _fe.Name == name select _fe; if (fel.Count() > 0) { fe = fel.First(); } else { fe = new FileElement(FileAttributes.Directory, name); parent.AddChild(fe); } } if(fa == FileAttributes.Normal) fe.child = null; fe.FileAttr = fa; fe.BeChanged = true; return fe; } /// <summary> /// 被 FileBus.Client 调用 /// 根据 XPath,获取 FileElement 树 /// </summary> /// <param name="XPath"></param> /// <returns></returns> public FileElement SelectSingleNode(string XPath) { string[] parent = XPath.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries); if (parent.Length == 0)//根目录为 @"\" { return this; } FileElement fe = this; foreach (string name in parent) { var fel = from _fe in fe.child where _fe.Name == name select _fe; if (fel.Count() > 0) { fe = fel.First(); } else { return null; } } return fe; } #region 设定Update 标志位 /// <summary> /// 被 FileBus.Client 调用; /// 设置 路径 的 update = b /// </summary> /// <param name="XPath"></param> public bool SetUpdateFlag(string XPath, bool b) { //TODO FileElement fe = SelectSingleNode(XPath); if (fe != null) { fe.Update = b; } return b; } /// <summary> /// 当时间不一样时,update=true /// </summary> /// <param name="dt"></param> /// <returns></returns> public bool SetUpdateFlag(DateTime dt) { if (LastWriteTime != dt) { this.LastWriteTime = dt; this.Update = true; } return this.Update; } /// <summary> /// 从FileElement比较 时间 /// </summary> /// <param name="element"></param> /// <returns></returns> private bool SetUpdateFlag(FileElement element) { CreateTime = element.CreateTime; if (LastWriteTime.ToString() != element.LastWriteTime.ToString()) { Update = true; } LastWriteTime = element.LastWriteTime; if (Size != element.Size) { DownloadSize = element.DownloadSize; } Size = element.Size; if (DownloadSize < element.DownloadSize) DownloadSize = element.DownloadSize; return this.Update; } #endregion #region 更新 /// <summary> /// 被 FileBus.Client 调用; /// 把element 更新到 指定的 路径; /// 当 hasChild=true 时,更新 element的子 element; /// 当 修改时间不一致时, 设置 update = true /// </summary> /// <param name="XPath">路径</param> /// <param name="fElement">源FileElement</param> /// <param name="needUpdateChild">需要更新child</param> /// <returns></returns> public FileElement ToUpdate(string XPath, FileElement element, bool needUpdateChild) { FileElement fe = SelectSingleNode(XPath); if(fe==null) { //没有该路径,需要创造 fe = CreateNode( XPath, element.FileAttr ); } fe.ToUpdate(element, needUpdateChild); return fe; } /// <summary> /// 判断子文件 当前修改时间是否与对象fElements 一致, /// 1.不一样则复制fElement的修改时间,且 标志为“需要更新” /// 2.当fElements有,但child 没的元素,child 添加且 标志为“需要更新” /// 3.当fElements没,但child 有的元素,child 删除且把被删除的输出del_Elements /// </summary> /// <param name="fElements">匹配的</param> /// <param name="del_Elements">被删除的</param> /// <returns></returns> //public bool ToUpdate(IEnumerable<FileElement> fElements, out List<FileElement> del_Elements) //{ // del_Elements = null; // if (FileAttr != FileAttributes.Directory) // return false; // //添加 // foreach (FileElement fe in fElements) // { // var fel = from _fe in child where _fe.Name == fe.Name select _fe; // if (fel.Count() > 0) // { // FileElement f = fel.First(); // f.SetUpdateFlag(fe); // } // else // { // //添加到本地 // FileElement f = new FileElement(fe.FileAttr, fe.Name) // { // LastWriteTime = fe.LastWriteTime, // CreateTime = fe.CreateTime, // Size = fe.Size // }; // AddChild(f); // f.SetUpdateFlag(fe); // } // } // //删除 // List<FileElement> del = new List<FileElement>(); // { // var fel = from _fe in child // where // (from _fe1 in fElements where _fe1.Name == _fe.Name select _fe1).Count() == 0 // select _fe; // del.AddRange(fel); // for (int i = 0; i < fel.Count(); i++) // { // child.Remove(fel.ElementAt(i)); // } // } // return true; //} /// <summary> /// 判断当前修改时间是否与源FileElement 一致,不一样则 /// 复制fElement的修改时间,且 标志为需要更新 /// </summary> /// <param name="fElement">源FileElement</param> /// <param name="needUpdateChild">需要更新child</param> /// <returns></returns> public bool ToUpdate(FileElement fElement, bool needUpdateChild) { bool ret = SetUpdateFlag(fElement); if (needUpdateChild) { if (fElement.child == null) { if (child != null) { child.Clear(); } } else { //添加 foreach (FileElement fe in fElement.child) { var fel = from _fe in child where _fe.Name == fe.Name select _fe; if (fel.Count() > 0) { FileElement f = fel.First(); f.SetUpdateFlag(fe); } else { //添加到本地 FileElement f = new FileElement(fe.FileAttr, fe.Name) { LastWriteTime = fe.LastWriteTime, CreateTime = fe.CreateTime, Size = fe.Size }; AddChild(f); } } //删除多余!!!! for (int i = 0; i < child.Count(); i++) { FileElement fe = child[i]; var fel = from _fe in fElement.child where _fe.Name == fe.Name select _fe; if (fel.Count() == 0) { //不存在,删除 child.Remove(fe); i--; } } } } return ret; } #endregion #region 创建FileElement public FileElement() { } //被 FileBus.Client 调用 new FileElement(FileAttributes.Directory, @"\"); public FileElement(FileAttributes fa, string name) { this.Name = name; if (fa != FileAttributes.Directory && fa != FileAttributes.Normal) fa = FileAttributes.Directory; FileAttr = fa; LastWriteTime = DateTime.Now; Update = true; if (fa == FileAttributes.Directory) { //child = new List<FileElement>(); child = new ObservableCollection<FileElement>(); } } /// <summary> /// 被 FileBus.Client 调用 /// 把格式为 “sysparam.ini F 2015/4/20 10:55:20” 字符串 转为单个FileElement /// </summary> /// <param name="fileinfo"></param> /// <returns></returns> //public static FileElement Parse(string fileinfo) //{ // //格式 sysparam.ini F 2015/4/20 10:55:20 // string[] blocks = fileinfo.Split(' '); // string path=blocks[0]; // FileAttributes fa; // if(blocks[1]=="F") // fa=FileAttributes.Normal; // else// if(blocks[1]=="D") // fa=FileAttributes.Directory; // DateTime mtime = DateTime.Parse(blocks[2] + " " + blocks[3]); // FileElement fe = new FileElement(fa, path); // fe.LastWriteTime = mtime; // return fe; //} #endregion #region INotifyPropertyChanged 成员 protected void NotifyPropertyChanged(string propertyname) { if (PropertyChanged != null) PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyname)); } public event PropertyChangedEventHandler PropertyChanged; #endregion } }