一个打包文件导入器
不光是敲代码,最近连打包也做了,各种各样的打包要解释:给仪器打包,吃饭时帮同事打包饭菜,给生成好的程序打包。由于这里是博客园,仪器打包和饭菜打包不能说太多,不然有移出首页的危险。之前写了两篇关于安装包制作的博文了,这回继续写与安装包相关的。尽管现在有不少的打包工具,但是还用着VS来打包。
来说说背景,有这么个程序,他的完整代码我手上没有,每次打包都要搭档生成一份给我,这样就没法在项目输出那里把需要的文件(包括exe)塞进去,只能手动去添加,但是面对着多个文件夹,我只能用老黄牛的办法把它们都加进去。一般情况下,我只会把最新的文件替换过去就算了,不过如果添加了新文件,少添加了打包后的程序会不完整,检查的话又够呛的,我总算想到了一个方法,做个导入器,因为想起以前看过杨中科老师的视频,发现vs的项目文件其实就是个xml文件来的,通过改xml把需要的文件加进去,比手工去加要省事。
于是我就很兴奋地打开了那个vdproj文件,与C#的项目不同,vdproj里面的结构有点像是json那种的,这样要改的话,就没xml那么简单了。
经过我的查找,发现文件信息是记录在”Files”{}里面的,举个例子
"File" { "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F08947D6FAEF4B8BBC64541285AF3FD3" { "SourcePath" = "8:C:\\Users\\HopeGi\\Desktop\\temp\\案例Scork\\17-01\\TestInetAddress.class" "TargetName" = "8:TestInetAddress.class" "Tag" = "8:" "Folder" = "8:_4264EA06455D4895BA8C4B6449880985" "Condition " = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } }
一个文件,就是从第3行到导数第二行结束,这么大堆的信息,我能理解的只有几个
- SourcePath:文件的源路径
- TargetName:文件在VS里显示的文件名
- Folder:解包后所在的文件夹
后来再经过我的探究发现这里的三个GUID码,第一个放在括号里头的,如果放在“应用程序文件夹”里面的,统一是1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE,其他文件夹的我没试过,也不清楚;后面有冒号和下划线跟着的那个(就是F08947D6FAEF4B8BBC64541285AF3FD3),这个是随机生成的,这个随机码作为这个文件的唯一标识,还有另一个用途接下来会说到的;最后Folder的随机码下面也会说到。
文件夹的话,所有内容都放在”Folder”{}里面的,这里我用到的是“应用程序文件夹”而已。
"{3C67513D-01DD-4637-8A68-80971EB9504F}:_EDF54782651E4E74B7A04AA76C65434E" { "DefaultLocation" = "8:[ProgramFilesFolder][Manufacturer]\\[ProductName]" "Name" = "8:#1925" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:TARGETDIR" "Folders" { } }
我是靠它的DefaultLocation认出来的,文件夹的子文件夹都是放在”Folders”{}里面的,例如其中一个文件夹的信息就这样子
"{9EF0B969-E518-4E46-987F-47570745A589}:_4264EA06455D4895BA8C4B6449880985" { "Name" = "8:17-01" "Property" = "8:_F9CDAE22FD634267992D47E28FAA77E7" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Folders" { } }
这里也有三个GUID码,第一个对于放在“应用程序文件夹”里面的,统一是9EF0B969-E518-4E46-987F-47570745A589,而第二个是随机生成一个就行了,但这个是用于标识这个文件夹的,而这个随机码是给文件那个”Folder”用的,至于第三个是"Property"的,我也不清楚它的用途。这里还有两个属性我知道是什么回事
- “Name”:文件夹的名字
- “Folders”:这个文件夹的子文件夹的集合。
这里还有另外一个东西"Hierarchy"{},有了这个,添加的文件才能在解决方案管理器显示出来。每一项的格式如下
"Entry" { "MsmKey" = "8:_F08947D6FAEF4B8BBC64541285AF3FD3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" }
这里有只有一个属性我知道是什么意思,不知道的就按回原样就行了,至于"MsmKey"这个就是对应文件的那个GUID码。
好了,了解了vdproj文件的结构之后,就可以通过代码改写vdproj文件,从而实现导入的效果。流程如下
- 分析需要导入的目录结构,包括文件夹的层次和文件
- 生成与vdproj格式相同的文件夹信息和文件信息
- 利用正则找出File,Folder,Hierachy这三部分的信息
- 替换vdproj文件的内容
这里要插一句,觉得VS分析vdproj的格式限制得太死了,就连"OwnerKey" = "8:_UNDEFINED"这类的,如果等号两边没有了空格,VS会分析不出来。
最后就介绍源码了。首先是两个实体类,分别用于记录文件夹信息和文件信息的
1 class SetupFileInfo 2 { 3 public string GUID_1 4 { get { return "1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE"; } } 5 public string SourcePath { get; set; } 6 public string TargetName { get; set; } 7 public string Folder { get; set; } 8 public string GUID_2 { get; set; } 9 10 #region 文字模板 11 private static string _defaultString = @" ""Condition "" = ""8:"" 12 ""Transitive"" = ""11:FALSE"" 13 ""Vital"" = ""11:TRUE"" 14 ""ReadOnly"" = ""11:FALSE"" 15 ""Hidden"" = ""11:FALSE"" 16 ""System"" = ""11:FALSE"" 17 ""Permanent"" = ""11:FALSE"" 18 ""SharedLegacy"" = ""11:FALSE"" 19 ""PackageAs"" = ""3:1"" 20 ""Register"" = ""3:1"" 21 ""Exclude"" = ""11:FALSE"" 22 ""IsDependency"" = ""11:FALSE"" 23 ""IsolateTo"" = ""8:"" 24 } 25 "; 26 #endregion 27 28 /// <summary> 29 /// 生成vdproj的文件的字符串 30 /// </summary> 31 /// <returns></returns> 32 public string CreateFileItemInfo() 33 { 34 StringBuilder sb = new StringBuilder(); 35 sb.AppendFormat("\r\n\"{{{0}}}:{1}\" \r\n", GUID_1, GUID_2); 36 sb.AppendFormat("{{\r\n \"SourcePath\" = \"8:{0}\" \r\n", SourcePath); 37 sb.AppendFormat("\"TargetName\" = \"8:{0}\" \r\n", TargetName); 38 sb.AppendLine("\"Tag\" = \"8:\""); 39 sb.AppendFormat("\"Folder\" = \"8:{0}\" \r\n",Folder); 40 sb.AppendLine(_defaultString); 41 42 return sb.ToString(); 43 } 44 }
1 class SetupDirectoryInfo 2 { 3 public static string GUID_1 4 { get { return "9EF0B969-E518-4E46-987F-47570745A589"; } } 5 public string GUID_2 { get; set; } 6 public string Property { get; set; } 7 public string Name { get; set; } 8 public List<SetupDirectoryInfo> Folders { get; set; } 9 public List<SetupFileInfo> Files { get; set; } 10 11 /// <summary> 12 /// 生成当前目录和子目录的所有文件的字符串 13 /// </summary> 14 /// <returns></returns> 15 internal string CreateFilesString() 16 { 17 StringBuilder sb = new StringBuilder(); 18 19 foreach (SetupFileInfo item in Files) 20 sb.Append(item.CreateFileItemInfo()); 21 22 foreach (SetupDirectoryInfo item in Folders) 23 sb.Append(item.CreateFilesString()); 24 25 return sb.ToString(); 26 } 27 28 /// <summary> 29 /// 生成当前目录及子目录的文件夹字符串 30 /// </summary> 31 /// <returns></returns> 32 internal string CreateFoldersString() 33 { 34 StringBuilder sb = new StringBuilder(); 35 foreach (SetupDirectoryInfo item in Folders) 36 sb.Append(item.CreateFoldersString()); 37 38 string result = BuildCurrentFolderString().Replace("$$", sb.ToString()); 39 return result; 40 } 41 42 /// <summary> 43 /// 供解决方案资源管理器用 44 /// </summary> 45 /// <returns></returns> 46 internal string CreateHierarchyString() 47 { 48 StringBuilder sb = new StringBuilder(); 49 foreach (SetupFileInfo file in Files) 50 { 51 sb.AppendLine("\r\n\"Entry\"\r\n{"); 52 sb.AppendFormat("\"MsmKey\" = \"8:{0}\"\r\n",file.GUID_2); 53 sb.AppendLine("\"OwnerKey\" = \"8:_UNDEFINED\"\r\n\"MsmSig\" = \"8:_UNDEFINED\"\r\n}\r\n"); 54 } 55 foreach (SetupDirectoryInfo folder in Folders) 56 sb.Append(folder.CreateHierarchyString()); 57 58 return sb.ToString(); 59 } 60 61 #region 文字模板 62 private static string _defaultString = @" ""AlwaysCreate"" = ""11:FALSE"" 63 ""Condition"" = ""8:"" 64 ""Transitive"" = ""11:FALSE"" 65 ""Folders"" 66 { 67 $$ 68 } 69 } 70 "; 71 #endregion 72 73 /// <summary> 74 /// 生成vdproj文件的文件夹字符串 75 /// </summary> 76 /// <returns></returns> 77 private string BuildCurrentFolderString() 78 { 79 StringBuilder sb = new StringBuilder(); 80 sb.AppendFormat("\r\n\"{{9EF0B969-E518-4E46-987F-47570745A589}}:{0}\" \r\n", GUID_2); 81 sb.AppendFormat("{{\r\n\"Name\" = \"8:{0}\" \r\n",Name); 82 sb.AppendFormat("\"Property\" = \"8:{0}\" \r\n ", Property); 83 sb.Append(_defaultString); 84 return sb.ToString(); 85 } 86 }
这两个实体类主要存储着文件和文件夹的信息,还提供了生成当前文件或文件夹对象的字符串的方法。对于SetupDirectoryInfo类里面还提供三个方法,是生成当前目录及子目录的所有文件夹字符串,当前目录及子目录所有文件的字符串的方法。
此外还需要两个工具类一个是用于GUID的生成
1 class GUIDCreater 2 { 3 public static string CreateGUID2() 4 { 5 string result = "_"+Guid.NewGuid().ToString().Replace("-","").ToUpper(); 6 return result; 7 } 8 }
还有对特殊字符的处理,经实践发现,如果文件或文件名存在着一些特殊字符(暂时发现美元符号‘$’)会使得正则处理的时候出错。于是先把那些特殊字符转换一下,等到正则处理完再把它还原成特殊字符。存储特殊字符和暂代字符串是用一个Dictionary。
1 class SpecialCharacter 2 { 3 private static Dictionary<string,string> innerDictory; 4 private static Dictionary<string, string> InnerDictory 5 { 6 get 7 { 8 if (innerDictory == null) 9 innerDictory = new Dictionary<string, string>(); 10 return innerDictory; 11 } 12 } 13 14 public static void AddCharacter(string value) 15 { 16 if (value.Length != 1) 17 throw new Exception("value' length too long"); 18 if (!InnerDictory.ContainsKey(value)) 19 InnerDictory.Add(value, GUIDCreater.CreateGUID2()); 20 } 21 22 public static void ClearRecord() 23 { 24 InnerDictory.Clear(); 25 } 26 27 /// <summary> 28 /// 将特殊的字符转换成其他字符串 29 /// </summary> 30 /// <param name="content"></param> 31 /// <returns></returns> 32 public static string ChangeSpecialCharacter(string content) 33 { 34 foreach (KeyValuePair<string,string> iDic in InnerDictory) 35 { 36 if (content.Contains(iDic.Key)) 37 content=content.Replace(iDic.Key,iDic.Value); 38 } 39 return content; 40 } 41 42 /// <summary> 43 /// 将转换后的字符串还原成原来的特殊字符 44 /// </summary> 45 /// <param name="content"></param> 46 /// <returns></returns> 47 public static string RecoverSpecialCharacter(string content) 48 { 49 foreach (KeyValuePair<string,string> iDic in InnerDictory) 50 { 51 if (content.Contains(iDic.Value)) 52 content=content.Replace(iDic.Value,iDic.Key); 53 } 54 return content; 55 } 56 }
然后就是完成导入任务的类了,其中下面这个方法则是导入的方法
1 public void ImportDirectory(string path,string vdproj, ImportType type) 2 { 3 Initial();//一些导入前的操作,这里实际上是给特殊字符的列表中添加特殊字符 4 SetupDirectoryInfo dirInfo= CreateDirecotryTree(path);//分析给定目录下所有的子文件夹和文件 5 string strFiles =SpecialCharacter.ChangeSpecialCharacter( dirInfo.CreateFilesString());//生成所有文件字符串 6 string strFolders = SpecialCharacter.ChangeSpecialCharacter( dirInfo.CreateFoldersString());//生成所有文件夹字符串 7 string strHierarchy = SpecialCharacter.ChangeSpecialCharacter( dirInfo.CreateHierarchyString());//生成所有Hierachy字符串 8 string vdprojContent=SpecialCharacter.ChangeSpecialCharacter( File.ReadAllText(vdproj,Encoding.UTF8));//读取vdproj文件内容 9 File.Copy(vdproj, vdproj + ".bak",true);//备份vdproj文件10 11 //判断当前对“应用程序程序文件夹”的内容是追加还是覆盖 12 if (type == ImportType.Append) 13 vdprojContent=SpecialCharacter.RecoverSpecialCharacter( AppendContent(vdprojContent,strHierarchy, strFiles, strFolders)); 14 else 15 vdprojContent=SpecialCharacter.RecoverSpecialCharacter( OverWriteContent(vdprojContent,strHierarchy, strFiles, strFolders)); 16 File.WriteAllText(vdproj, vdprojContent,Encoding.UTF8); //保存更改后的vdproj文件 17 Finish();//清除特殊字符列表的内容 18 }
这个类的其他方法就不一一列举了,在博文地步会附上整份源码。为了让操作方便一点,我自己还做了一个图形界面。
好像做了这个导入器,是很笨的一个做法,估计解决这个文件结构难题的办法多的是,本来我用VS来打包,没用其他的工具,也已经很笨了。我有个搭档就跟我说,可以把那堆难缠的文件夹弄一个压缩包,在安装的时候解压就行了。喝喝!但是我没用他的那种方案。
最近好像没时间写博文了,有空就写一下吧!我还是想更新我的博客的。
1 public class SetupImporter 2 { 3 #region Regex 4 private static string _regFilesInner = @"(?<=""File""\r\n\s*{)[^{}]*(((?'Open'{)[^{}]*)+((?'-Open'})[^{}]*)+)*(?(Open)(?!))(?=})"; 5 private static string _regFoldersInner = @"(?<=""{3C67513D-01DD-4637-8A68-80971EB9504F}:_\w*""[\r\n\s{""#\w=:\[\]\\]*""Folders""\r\n\s*{)[^{}]*(((?'Open'{)[^{}]*)+((?'-Open'})[^{}]*)+)*(?(Open)(?!))(?=})"; 6 private static string _regHierachyInner = @"(?<=""Hierarchy""\r\n\s*{)[^{}]*(((?'Open'{)[^{}]*)+((?'-Open'})[^{}]*)+)*(?(Open)(?!))(?=})"; 7 8 private static string _regFilesOuter = @"""File""\r\n\s*{[^{}]*(((?'Open'{)[^{}]*)+((?'-Open'})[^{}]*)+)*(?(Open)(?!))}"; 9 private static string _regFoldersOuter = @"""{3C67513D-01DD-4637-8A68-80971EB9504F}:_\w*""[\r\n\s{""#\w=:\[\]\\]*""Folders""\r\n\s*{[^{}]*(((?'Open'{)[^{}]*)+((?'-Open'})[^{}]*)+)*(?(Open)(?!))}\r\n\s*}"; 10 private static string _regHierachyOuter = @"""Hierarchy""\r\n\s*{[^{}]*(((?'Open'{)[^{}]*)+((?'-Open'})[^{}]*)+)*(?(Open)(?!))}"; 11 #endregion 12 13 public void ImportDirectory(string path,string vdproj, ImportType type) 14 { 15 Initial(); 16 SetupDirectoryInfo dirInfo= CreateDirecotryTree(path); 17 string strFiles =SpecialCharacter.ChangeSpecialCharacter( dirInfo.CreateFilesString()); 18 string strFolders = SpecialCharacter.ChangeSpecialCharacter( dirInfo.CreateFoldersString()); 19 string strHierarchy = SpecialCharacter.ChangeSpecialCharacter( dirInfo.CreateHierarchyString()); 20 string vdprojContent=SpecialCharacter.ChangeSpecialCharacter( File.ReadAllText(vdproj,Encoding.UTF8)); 21 File.Copy(vdproj, vdproj + ".bak",true); 22 23 if (type == ImportType.Append) 24 vdprojContent=SpecialCharacter.RecoverSpecialCharacter( AppendContent(vdprojContent,strHierarchy, strFiles, strFolders)); 25 else 26 vdprojContent=SpecialCharacter.RecoverSpecialCharacter( OverWriteContent(vdprojContent,strHierarchy, strFiles, strFolders)); 27 File.WriteAllText(vdproj, vdprojContent,Encoding.UTF8); 28 Finish(); 29 } 30 31 private SetupDirectoryInfo CreateDirecotryTree(string path) 32 { 33 DirectoryInfo root = new DirectoryInfo(path); 34 35 SetupDirectoryInfo dir = new SetupDirectoryInfo(); 36 dir.Name = root.Name; 37 dir.GUID_2 = GUIDCreater.CreateGUID2(); 38 dir.Property = GUIDCreater.CreateGUID2(); 39 40 FileInfo[] files = root.GetFiles(); 41 List<SetupFileInfo> fileList = new List<SetupFileInfo>(files.Length); 42 SetupFileInfo fileItem = null; 43 foreach (FileInfo file in files) 44 { 45 fileItem = new SetupFileInfo(); 46 47 fileItem.GUID_2 = GUIDCreater.CreateGUID2(); 48 fileItem.SourcePath = file.FullName.Replace("\\","\\\\"); 49 fileItem.TargetName = file.Name; 50 fileItem.Folder = dir.GUID_2; 51 52 fileList.Add(fileItem); 53 } 54 dir.Files = fileList; 55 56 DirectoryInfo[] dirs = root.GetDirectories(); 57 List<SetupDirectoryInfo> folderList = new List<SetupDirectoryInfo>(dirs.Length); 58 SetupDirectoryInfo dirItem = null; 59 foreach (DirectoryInfo item in dirs) 60 { 61 dirItem = CreateDirecotryTree(item.FullName); 62 folderList.Add(dirItem); 63 } 64 dir.Folders = folderList; 65 66 return dir; 67 } 68 69 private string OverWriteContent(string vdprojContent, string strHierarchy, string strFiles, string strFolders) 70 { 71 vdprojContent = Regex.Replace(vdprojContent, _regFilesInner, strFiles ); 72 vdprojContent = Regex.Replace(vdprojContent, _regFoldersInner, strFolders ); 73 vdprojContent = Regex.Replace(vdprojContent, _regHierachyInner, strHierarchy ); 74 75 return vdprojContent; 76 } 77 78 private string AppendContent(string vdprojContent,string strHierarchy, string strFiles, string strFolders) 79 { 80 string macthFiles = Regex.Match(vdprojContent, _regFilesInner).Value; 81 string macthFolders = Regex.Match(vdprojContent, _regFoldersInner).Value; 82 string matchHierachy = Regex.Match(vdprojContent, _regHierachyInner).Value; 83 strFiles += macthFiles; 84 strFolders += macthFolders; 85 strHierarchy += matchHierachy; 86 87 vdprojContent = OverWriteContent(vdprojContent,strHierarchy, strFiles, strFolders); 88 return vdprojContent; 89 } 90 91 private void Initial() 92 { 93 SpecialCharacter.AddCharacter("$"); 94 } 95 96 private void Finish() 97 { 98 SpecialCharacter.ClearRecord(); 99 } 100 } 101 102 public enum ImportType 103 { 104 Append, 105 OverWrite 106 } 107 108 class SetupFileInfo 109 { 110 public string GUID_1 111 { get { return "1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE"; } } 112 public string SourcePath { get; set; } 113 public string TargetName { get; set; } 114 public string Folder { get; set; } 115 public string GUID_2 { get; set; } 116 117 #region 文字模板 118 private static string _defaultString = @" ""Condition "" = ""8:"" 119 ""Transitive"" = ""11:FALSE"" 120 ""Vital"" = ""11:TRUE"" 121 ""ReadOnly"" = ""11:FALSE"" 122 ""Hidden"" = ""11:FALSE"" 123 ""System"" = ""11:FALSE"" 124 ""Permanent"" = ""11:FALSE"" 125 ""SharedLegacy"" = ""11:FALSE"" 126 ""PackageAs"" = ""3:1"" 127 ""Register"" = ""3:1"" 128 ""Exclude"" = ""11:FALSE"" 129 ""IsDependency"" = ""11:FALSE"" 130 ""IsolateTo"" = ""8:"" 131 } 132 "; 133 #endregion 134 135 /// <summary> 136 /// 生成vdproj的文件的字符串 137 /// </summary> 138 /// <returns></returns> 139 public string CreateFileItemInfo() 140 { 141 StringBuilder sb = new StringBuilder(); 142 sb.AppendFormat("\r\n\"{{{0}}}:{1}\" \r\n", GUID_1, GUID_2); 143 sb.AppendFormat("{{\r\n \"SourcePath\" = \"8:{0}\" \r\n", SourcePath); 144 sb.AppendFormat("\"TargetName\" = \"8:{0}\" \r\n", TargetName); 145 sb.AppendLine("\"Tag\" = \"8:\""); 146 sb.AppendFormat("\"Folder\" = \"8:{0}\" \r\n",Folder); 147 sb.AppendLine(_defaultString); 148 149 return sb.ToString(); 150 } 151 } 152 153 class SetupDirectoryInfo 154 { 155 public static string GUID_1 156 { get { return "9EF0B969-E518-4E46-987F-47570745A589"; } } 157 public string GUID_2 { get; set; } 158 public string Property { get; set; } 159 public string Name { get; set; } 160 public List<SetupDirectoryInfo> Folders { get; set; } 161 public List<SetupFileInfo> Files { get; set; } 162 163 /// <summary> 164 /// 生成当前目录和子目录的所有文件的字符串 165 /// </summary> 166 /// <returns></returns> 167 internal string CreateFilesString() 168 { 169 StringBuilder sb = new StringBuilder(); 170 171 foreach (SetupFileInfo item in Files) 172 sb.Append(item.CreateFileItemInfo()); 173 174 foreach (SetupDirectoryInfo item in Folders) 175 sb.Append(item.CreateFilesString()); 176 177 return sb.ToString(); 178 } 179 180 /// <summary> 181 /// 生成当前目录及子目录的文件夹字符串 182 /// </summary> 183 /// <returns></returns> 184 internal string CreateFoldersString() 185 { 186 StringBuilder sb = new StringBuilder(); 187 foreach (SetupDirectoryInfo item in Folders) 188 sb.Append(item.CreateFoldersString()); 189 190 string result = BuildCurrentFolderString().Replace("$$", sb.ToString()); 191 return result; 192 } 193 194 /// <summary> 195 /// 供解决方案资源管理器用 196 /// </summary> 197 /// <returns></returns> 198 internal string CreateHierarchyString() 199 { 200 StringBuilder sb = new StringBuilder(); 201 foreach (SetupFileInfo file in Files) 202 { 203 sb.AppendLine("\r\n\"Entry\"\r\n{"); 204 sb.AppendFormat("\"MsmKey\" = \"8:{0}\"\r\n",file.GUID_2); 205 sb.AppendLine("\"OwnerKey\" = \"8:_UNDEFINED\"\r\n\"MsmSig\" = \"8:_UNDEFINED\"\r\n}\r\n"); 206 } 207 foreach (SetupDirectoryInfo folder in Folders) 208 sb.Append(folder.CreateHierarchyString()); 209 210 return sb.ToString(); 211 } 212 213 #region 文字模板 214 private static string _defaultString = @" ""AlwaysCreate"" = ""11:FALSE"" 215 ""Condition"" = ""8:"" 216 ""Transitive"" = ""11:FALSE"" 217 ""Folders"" 218 { 219 $$ 220 } 221 } 222 "; 223 #endregion 224 225 /// <summary> 226 /// 生成vdproj文件的文件夹字符串 227 /// </summary> 228 /// <returns></returns> 229 private string BuildCurrentFolderString() 230 { 231 StringBuilder sb = new StringBuilder(); 232 sb.AppendFormat("\r\n\"{{9EF0B969-E518-4E46-987F-47570745A589}}:{0}\" \r\n", GUID_2); 233 sb.AppendFormat("{{\r\n\"Name\" = \"8:{0}\" \r\n",Name); 234 sb.AppendFormat("\"Property\" = \"8:{0}\" \r\n ", Property); 235 sb.Append(_defaultString); 236 return sb.ToString(); 237 } 238 } 239 240 class GUIDCreater 241 { 242 public static string CreateGUID2() 243 { 244 string result = "_"+Guid.NewGuid().ToString().Replace("-","").ToUpper(); 245 return result; 246 } 247 } 248 249 class SpecialCharacter 250 { 251 private static Dictionary<string,string> innerDictory; 252 private static Dictionary<string, string> InnerDictory 253 { 254 get 255 { 256 if (innerDictory == null) 257 innerDictory = new Dictionary<string, string>(); 258 return innerDictory; 259 } 260 } 261 262 public static void AddCharacter(string value) 263 { 264 if (value.Length != 1) 265 throw new Exception("value' length too long"); 266 if (!InnerDictory.ContainsKey(value)) 267 InnerDictory.Add(value, GUIDCreater.CreateGUID2()); 268 } 269 270 public static void ClearRecord() 271 { 272 InnerDictory.Clear(); 273 } 274 275 /// <summary> 276 /// 将特殊的字符转换成其他字符串 277 /// </summary> 278 /// <param name="content"></param> 279 /// <returns></returns> 280 public static string ChangeSpecialCharacter(string content) 281 { 282 foreach (KeyValuePair<string,string> iDic in InnerDictory) 283 { 284 if (content.Contains(iDic.Key)) 285 content=content.Replace(iDic.Key,iDic.Value); 286 } 287 return content; 288 } 289 290 /// <summary> 291 /// 将转换后的字符串还原成原来的特殊字符 292 /// </summary> 293 /// <param name="content"></param> 294 /// <returns></returns> 295 public static string RecoverSpecialCharacter(string content) 296 { 297 foreach (KeyValuePair<string,string> iDic in InnerDictory) 298 { 299 if (content.Contains(iDic.Value)) 300 content=content.Replace(iDic.Value,iDic.Key); 301 } 302 return content; 303 } 304 }