|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
IntroductionWhen dealing with zip files you have a few choices: use native APIs from third party Dlls, java APIs or .Net APIs. BackgroundIn order to use Microsoft's API for multi-file zips and Java streams, you have to add vjslib.dll and vjslibcw.dll Listing the content of a zip fileBelow you could see a snippet of code edited for simplicity that enumerates the files in the archive: public static List<string > GetZipFileNames(string zipFile) { ZipFile zf = null; List<string > list = new List<string >(); try { zf = new ZipFile(zipFile); java.util.Enumeration enu = zf.entries(); while (enu.hasMoreElements()) { ZipEntry zen = enu.nextElement() as ZipEntry; if (zen.isDirectory()) continue;//ignore directories list.Add(zen.getName()); } } catch(Exception ex) { throw new ApplicationException("Please drag/drop only valid zip files\nthat are not password protected.",ex); } finally { if (zf != null) zf.close(); } return list; } As you probably noticed ZipEntry and ZipFile are easy to use for this goal. Zipping files from a folderBelow you could see a helper method used to zip the files from a folder: private static void _CreateZipFromFolder(string Folder, IsFileStrippableDelegate IsStrip) { System.IO.DirectoryInfo dirInfo = new System.IO.DirectoryInfo(Folder); System.IO.FileInfo[] files = dirInfo.GetFiles("*");//all files foreach (FileInfo file in files) { if (IsStrip != null && IsStrip(file.FullName)) continue;//skip, don't zip it java.io.FileInputStream instream = new java.io.FileInputStream(file.FullName); int bytes = 0; string strEntry = file.FullName.Substring(m_trimIndex); _zos.putNextEntry(new ZipEntry(strEntry)); while ((bytes = instream.read(_buffer, 0, _buffer.Length)) > 0) { _zos.write(_buffer, 0, bytes); } _zos.closeEntry(); instream.close(); } System.IO.DirectoryInfo[] folders = null; folders = dirInfo.GetDirectories("*"); if (folders != null) { foreach (System.IO.DirectoryInfo folder in folders) { _CreateZipFromFolder(folder.FullName, IsStrip); } } } The IsStrip delegate acts as a filter that trashes the unwanted files. Unzipping files from a zip fileBelow you could see an edited for brevity piece of code used to unzip the files from a zip: ZipInputStream zis = null; zis = new ZipInputStream(new java.io.FileInputStream(file)); ZipEntry ze = null; while ((ze = zis.getNextEntry()) != null) { if (ze.isDirectory()) continue;//ignore directories string fname = ze.getName(); bool bstrip = IsStrip != null && IsStrip(fname); if (!bstrip) { //unzip entry int bytes = 0; FileStream filestream = null; BinaryWriter w = null; string filePath = Folder + @"\" + fname; if(!Directory.Exists(Path.GetDirectoryName(filePath))) Directory.CreateDirectory(Path.GetDirectoryName(filePath)); filestream = new FileStream(filePath, FileMode.Create); w = new BinaryWriter(filestream); while ((bytes = zis.read(_buffer, 0, _buffer.Length)) > 0) { for (int i = 0; i < bytes; i++) { unchecked { w.Write((byte)_buffer[i]); } } } } zis.closeEntry(); w.Close(); filestream.Close(); } if (zis != null) zis.close(); } Again the IsStrip delegate acts as a filter that trashes the unwanted files. Changing the zip fileYou can not directly modify a zip file. However you can create another zip and copy only select files in it. public static void StripZip(string zipFile, List<string > trashFiles) { ZipOutputStream zos = null; ZipInputStream zis = null; //remove 'zip' extension bool bsuccess = true; string strNewFile = zipFile.Remove(zipFile.Length - 3, 3) + "tmp"; zos = new ZipOutputStream(new java.io.FileOutputStream(strNewFile)); zis = new ZipInputStream(new java.io.FileInputStream(zipFile)); ZipEntry ze = null; while ((ze = zis.getNextEntry()) != null) { if (ze.isDirectory()) continue;//ignore directories string fname = ze.getName(); bool bstrip = trashFiles.Contains(fname); if (!bstrip) { //copy the entry from zis to zos int bytes = 0; //deal with password protected files zos.putNextEntry(new ZipEntry(fname)); while ((bytes = zis.read(_buffer, 0, _buffer.Length)) > 0) { zos.write(_buffer, 0, bytes); } zis.closeEntry(); zos.closeEntry(); } } if (zis != null) zis.close(); if (zos != null) zos.close(); if (bsuccess) { System.IO.File.Delete(zipFile + ".old"); System.IO.File.Move(zipFile, zipFile + ".old"); System.IO.File.Move(strNewFile, zipFile); } else System.IO.File.Delete(strNewFile); } Improvements over the version 1.0To make this tool more attractive I've added some improvements of my own: The first one to notice <configuration> <maskRow maskField="*.plg" / > <maskRow maskField=".opt" / > <maskRow maskField=".ncb" / > <maskRow maskField=".suo" / > <maskRow maskField="*.pdb" / > ...... </configuration> Reading data from the config fileNotice that in the application configuration file we keep not only the appSetttings node, XmlDocument xd = new XmlDocument(); xd.Load(cfgxmlpath); //use plain xml xpath for the rest m_paths.Clear(); XmlNode xnpath = xd["configuration"]["paths"]; if(xnpath!=null) { foreach(XmlNode xn in xnpath.ChildNodes) { m_paths.Add(xn.InnerXml); } } XmlNode xnfile = xd["configuration"]["files"]; if(xnfile!=null) { foreach(XmlNode xn in xnfile.ChildNodes) { m_files.Add(xn.InnerXml); } } //use the data set m_extensions.Clear(); _dataSet = new DataSet("configuration"); DataTable mytable = new DataTable("maskRow"); DataColumn exColumn = new DataColumn("maskField", Type.GetType("System.String"), null, MappingType.Attribute); mytable.Columns.Add(exColumn); _dataSet.Tables.Add(mytable); _dataSet.Tables[0].ReadXml(MainForm.cfgxmlpath); for (int i = 0; i < _dataSet.Tables[0].Rows.Count; i++) { DataRow row = _dataSet.Tables[0].Rows[i]; string val = row[0].ToString().ToLower(); if (val.Length > 0)//no empty mask { //.....code eliminated for brevity } else { //don't show empty rows row.Delete(); } } _dataSet.Tables[0].AcceptChanges(); Writing data into the config fileUsing WriteXml from the dataSet will eliminate the data that does not belong to the table. XmlDocument xd = new XmlDocument(); //get the original xd.Load(MainForm.cfgxmlpath); //save nodes not part of the dataset XmlNode xnpath = xd["configuration"]["paths"]; XmlNode xnfile = xd["configuration"]["files"]; XmlNode lastFolderpath = xd["configuration"]["LastUsedFolder"]; //write the masks _dataSet.WriteXml(MainForm.cfgxmlpath); //restore the old saved nodes xd.Load(MainForm.cfgxmlpath); if(xnpath != null) xd.DocumentElement.AppendChild(xnpath); if (xnfile != null) xd.DocumentElement.AppendChild(xnfile); if (lastFolderpath != null) xd.DocumentElement.AppendChild(lastFolderpath); xd.Save(MainForm.cfgxmlpath); Using the wild chars for the filterI'm not going to get into details on this one, but as you've already noticed in the xml snippet,
Explorer folder context menuI've added some new functionality in regards to using the context menu from Explorer.
HistoryAs a utility I consider version 2.x to be an improvement over the old one. Version 2.3I've added email capability to the application using the Outlook wrapper and made other small enhancements.I also included the deployment project that created the msi file. | ||||||||||||||||||||