基于GZipStream的多文件压缩组件TGZipCompressBar实现

(原创文章,转载请注明来源:http://blog.csdn.net/hulihui)

    做分布式数据处理系统,经常要把下一级的数据库文件压缩后上报,做解压缩后导入。笔者使用Delphi时,用其Zlib单元实现的压缩组件HZlibBackup可以满足应用需求。在.NET 2.0引入压缩类后,使用GZipStream也可以定制自己的压缩组件。
   
    最初,笔者在章立民先生的书《Visual C# 2005文件IO与数据存取秘诀》中学习该组件用法,简单的太简单(一个文件)、复杂又过于复杂(类似WinZip),不满足笔者的多文件压缩、功能简单的需求。于是,Google了相关技术文章“ How to compress folders and multiple files with GZipStream”。该文的技术要点是: 
  1. 创建自己的GZip压缩文件格式;
  2. 将每个待压缩文件保存到一个大的临时合并文件中;
  3. 应用GZipStream压缩临时合并文件;
  4. 解压缩的过程是上述逆步骤。
    借用上述思路并适当改进后,笔者实现了一个多文件压缩组件TGZipCompressBar,主要思路如下:
  1. 压缩文件格式由三部分组成:文件头+{文件项+压缩文件}。文件头中保存:文件个数、文件项长度、压缩文件长,目的是解压缩时可以快速读取压缩文件的长度信息。文件项(TGZipFileEntry类)包括文件基本信息,如:文件名、长度、压缩长度、文件三个日期,文件日期用于解压缩后恢复其实际日期;
  2. 压缩文件时,先空出文件头部分,接着保存文件项部分、保存压缩文件部分,反复直到全部文件压缩完毕。此时,已经获得全部文件压缩后的长度数据。最后,将实际的文件头数据重写到压缩文件流的头部;
  3. 解压缩关键,必须先读出待解当前文件的压缩数据到MemoryStream,然后由GZipStream做解压缩。这个操作不能像压缩时,可以边读源文件边做压缩(似乎GZipStream底层实现不支持一块一块地读压缩后字节到输出流中)。因此,解压缩比压缩操作时间长点;
  4. 文件个数、文件项用简单的XOR做加密处理;
  5. 系统由三个类组成:压缩组件(TGZipCompressBar,继承笔者的TSmartProgressBar)、文件项(TGZipFileEntry)、简单加密类(TCipher),其中基类可以选择.NET的自带组件ProgressBar。
    实际测试表明,针对未做过压缩的文件,GZipStream的效率可以到40%左右,压缩速度也可以接受。而对于已经做了压缩处理的文件,GZipStream则效果极差,可能比原文件大50%左右!

    显然,进一步完善后可以实现WinRar的部分功能:1)解压缩指定文件;2)删除指定压缩文件;3)添加文件到压缩包;3)整个压缩文件加密;4)异步压缩处理;5)解压缩时保持文件夹;等等。

    TGZipCompressBar实现的窗体演示图如下,exe程序见本站资源: 基于GZip的多文件压缩组件TGZipCompressBar



  1. using System;
  2. using System.IO;
  3. using System.Text;
  4. using System.IO.Compression;
  5. using System.Collections;
  6. using System.Collections.Generic;
  7. using System.Runtime.Serialization.Formatters.Binary;
  8. using System.Windows.Forms;
  9. using System.ComponentModel;
  10. using System.Drawing;

  11. namespace CSUST.Data
  12. {
  13.     public class TGZipCompressBar : TSmartProgressBar
  14.     {
  15.         private const string m_FileExtensionName = ".gcf";  // gzip compress file
  16.         private const int m_MaxFileTotalLength = 1024 * 1024 * 1024;  // 1G
  17.         private const int m_ReadBufferSize = 8 * 1024;  // 8K

  18.         private string m_GZipFileName = string.Empty;
  19.         private string m_FolderDecompressTo = string.Empty;

  20.         private List<TGZipFileEntry> m_FileEntryList = new List<TGZipFileEntry>();
  21.         private List<TGZipFileEntry> m_PacketEntryList = new List<TGZipFileEntry>();

  22.         private byte[] m_ReadBuffer = new byte[m_ReadBufferSize];

  23.         private int m_NowMaxBarValue = 0;

  24.         public TGZipCompressBar()
  25.         {
  26.         }

  27.         public TGZipCompressBar(string gzipFileName)
  28.         {
  29.             this.Visible = false;
  30.             this.GZipFileName = gzipFileName;
  31.         }

  32.         public TGZipCompressBar(string gzipFileName, string decompressFolder)
  33.         {
  34.             this.Visible = false;
  35.             this.GZipFileName = gzipFileName;
  36.             this.FolderDecompressTo = decompressFolder;
  37.         }

  38.         /// <summary>
  39.         /// 按MS的模板, 只需要重载 Dispose 方法
  40.         /// </summary>
  41.         protected override void Dispose(bool disposing)
  42.         {
  43.             try
  44.             {
  45.                 if (disposing)
  46.                 {
  47.                     m_ReadBuffer = null;

  48.                     m_FileEntryList.Clear();
  49.                     m_FileEntryList = null;
  50.                     m_PacketEntryList.Clear();
  51.                     m_PacketEntryList = null;
  52.                 }
  53.             }
  54.             finally
  55.             {
  56.                 base.Dispose(disposing);
  57.             }
  58.         }

  59.         [Description("Set/Get GZip filename with extension .gcf")]
  60.         public string GZipFileName
  61.         {
  62.             get
  63.             {
  64.                 return m_GZipFileName;
  65.             }
  66.             set
  67.             {
  68.                 if (string.IsNullOrEmpty(value))
  69.                 {
  70.                     this.m_GZipFileName = value;
  71.                     this.m_PacketEntryList.Clear();
  72.                 }
  73.                 else
  74.                 {
  75.                     if (!this.IsValidFileName(value))
  76.                     {
  77.                         MessageBox.Show("GZip filename or it's path contains invalid char.");
  78.                     }
  79.                     else if (Path.GetExtension(value).ToUpper() != m_FileExtensionName.ToUpper())
  80.                     {
  81.                         MessageBox.Show("GZip filename must has extension " + m_FileExtensionName + ".");
  82.                     }
  83.                     else
  84.                     {
  85.                         this.m_PacketEntryList.Clear();
  86.                         this.m_GZipFileName = value;
  87.                     }
  88.                 }
  89.             }
  90.         }

  91.         [Description("Set/Get folder to decompress files")]
  92.         public string FolderDecompressTo
  93.         {
  94.             get
  95.             {
  96.                 return m_FolderDecompressTo;
  97.             }
  98.             set
  99.             {
  100.                 if (string.IsNullOrEmpty(value))
  101.                 {
  102.                     m_FolderDecompressTo = value;
  103.                 }
  104.                 else
  105.                 {
  106.                     if (!Directory.Exists(value))
  107.                     {
  108.                         MessageBox.Show("Decompress folder: " + value + " does not exists.");
  109.                     }
  110.                     else
  111.                     {
  112.                         if (value.EndsWith(@"/"))
  113.                         {
  114.                             m_FolderDecompressTo = value;
  115.                         }
  116.                         else
  117.                         {
  118.                             m_FolderDecompressTo = value + @"/";
  119.                         }
  120.                     }
  121.                 }
  122.             }
  123.         }

  124.         [Description("Get the default gzip file extension name.")]
  125.         public string DefaultFileExtentionName
  126.         {
  127.             get { return m_FileExtensionName; }
  128.         }

  129.         /// <summary>
  130.         /// Add a file to compress list.
  131.         /// </summary>
  132.         public bool AppendFile(string fileName)
  133.         {
  134.             if (string.IsNullOrEmpty(fileName) || !File.Exists(fileName))
  135.             {
  136.                 MessageBox.Show("GZipFileName is empty or does not exist.");
  137.                 return false;
  138.             }

  139.             TGZipFileEntry addFileInfo = new TGZipFileEntry(fileName);
  140.             long totalLength = addFileInfo.OriginalLength;

  141.             foreach (TGZipFileEntry fileEntry in m_FileEntryList)
  142.             {
  143.                 if (fileEntry.FileName.ToUpper() == addFileInfo.FileName.ToUpper())
  144.                 {
  145.                     MessageBox.Show("File: " + fileEntry.FileName + " has exists.");
  146.                     return false;
  147.                 }
  148.                 totalLength += fileEntry.OriginalLength;
  149.             }

  150.             if (totalLength > m_MaxFileTotalLength)
  151.             {
  152.                 MessageBox.Show("Total files length is over " + (m_MaxFileTotalLength / (1024 * 1024)).ToString() + "M.");
  153.                 return false;
  154.             }

  155.             m_FileEntryList.Add(addFileInfo);
  156.             return true;
  157.         }

  158.         /// <summary>
  159.         /// Clear all add files for compress.
  160.         /// </summary>
  161.         public void ClearFiles()
  162.         {
  163.             this.m_FileEntryList.Clear();
  164.             this.m_PacketEntryList.Clear();
  165.             this.SetStartPosition();
  166.         }

  167.         /// <summary>
  168.         /// Compress files with gzip algorithm.
  169.         /// </summary>
  170.         public bool Compress()
  171.         {
  172.             return this.Compressing();
  173.         }

  174.         /// <summary>
  175.         /// Decompress files from gzip file.
  176.         /// </summary>

  177.         public bool Decompress()
  178.         {
  179.             return this.Decompressing();
  180.         }

  181.         /// <summary>
  182.         /// If the gzipfile contains an assigned filename."
  183.         /// </summary>
  184.         public bool ContainsFile(string fileName)
  185.         {
  186.             if (!this.GetPacketEntryList())
  187.             {
  188.                 return false;
  189.             }

  190.             string realFileName = Path.GetFileName(fileName.Trim());
  191.             foreach (TGZipFileEntry fileEntry in m_PacketEntryList)
  192.             {
  193.                 if (fileEntry.FileName.ToUpper() == realFileName.ToUpper())
  194.                 {
  195.                     return true;
  196.                 }
  197.             }
  198.             return false;
  199.         }
  200.         
  201.         /// <summary>
  202.         /// string format: filename|fileLength|gzippedLength|lastModifiedDate|lastAccessDate|creationgDate|fullFileName
  203.         /// </summary>
  204.         public string GetFileEntryStringByFileName(string fileName)
  205.         {
  206.             if (!this.GetPacketEntryList())
  207.             {
  208.                 return null;
  209.             }

  210.             string realFileName = Path.GetFileName(fileName.Trim());
  211.             foreach (TGZipFileEntry fileEntry in m_PacketEntryList)
  212.             {
  213.                 if (fileEntry.FileName.ToUpper() == fileName.ToUpper())
  214.                 {
  215.                     return fileEntry.FormattedStr;
  216.                 }
  217.             }
  218.             return null;
  219.         }

  220.         /// <summary>
  221.         /// string format: filename|fileLength|gzippedLength|lastModifiedDate|lastAccessDate|creationgDate|fullFileName
  222.         /// </summary>
  223.         public List<string> GetFileEntryStringList()
  224.         {
  225.             if (!this.GetPacketEntryList())
  226.             {
  227.                 return null;
  228.             }

  229.             List<string> fileInfoList = new List<string>();

  230.             foreach (TGZipFileEntry fileEntry in m_PacketEntryList)
  231.             {
  232.                 fileInfoList.Add(fileEntry.FormattedStr);
  233.             }
  234.             return fileInfoList;
  235.         }

  236.         private bool Compressing()
  237.         {
  238.             bool opSuccess = false;

  239.             if (m_FileEntryList.Count == 0)
  240.             {
  241.                 MessageBox.Show("There has no compress file.");
  242.                 return opSuccess;
  243.             }

  244.             if (string.IsNullOrEmpty(m_GZipFileName))
  245.             {
  246.                 MessageBox.Show("GZipFileName is empty or not set.");
  247.                 return opSuccess;
  248.             }

  249.             this.SetApplicationCursor(Cursors.WaitCursor);

  250.             try
  251.             {
  252.                 using (FileStream outStream = new FileStream(m_GZipFileName, FileMode.Create, FileAccess.Write, FileShare.None))
  253.                 {
  254.                     this.m_PacketEntryList.Clear();
  255.                     this.WriteHeaderEmptyInfo(outStream);  // 写文件长度字节, 压缩结束后再填实际数据
  256.                     this.SetProgressBarMaxValue(false);
  257.                     this.ShowBeginStep();

  258.                     foreach (TGZipFileEntry fileEntry in m_FileEntryList)
  259.                     {
  260.                         this.SetProgressBarNowMaxValue(fileEntry, false);

  261.                         fileEntry.WriteEntryInfo(outStream);
  262.                         this.ShowProgressStep();
  263.                         this.CompressFile(fileEntry, outStream);
  264.                         this.m_PacketEntryList.Add(fileEntry);
  265.                     }

  266.                     this.WriteHeaderLengthInfo(outStream);  // 再填文件头, 此时有各块的长度信息
  267.                 }
  268.                 opSuccess = true;
  269.             }
  270.             catch (Exception err)
  271.             {
  272.                 throw new Exception(err.Message);
  273.             }
  274.             finally
  275.             {
  276.                 this.ShowFinalStep();
  277.                 this.SetApplicationCursor(Cursors.Default);
  278.             }
  279.             return opSuccess;
  280.         }

  281.         private bool Decompressing()
  282.         {
  283.             bool opSuccess = false;

  284.             if (string.IsNullOrEmpty(m_FolderDecompressTo))
  285.             {
  286.                 MessageBox.Show("Decompress folder is empty.");
  287.                 return opSuccess;
  288.             }

  289.             if (string.IsNullOrEmpty(m_GZipFileName))
  290.             {
  291.                 MessageBox.Show("GZipFileName is empty or does not exist.");
  292.                 return opSuccess;
  293.             }

  294.             this.SetApplicationCursor(Cursors.WaitCursor);

  295.             try
  296.             {
  297.                 using (FileStream srcStream = new FileStream(m_GZipFileName, FileMode.Open, FileAccess.Read, FileShare.Read))
  298.                 {
  299.                     this.m_PacketEntryList.Clear();
  300.                     this.ReadHeaderLengthInfo(srcStream);  // 获得各块的长度信息, 缺少文件项中的文件名、日期等信息
  301.                     this.SetProgressBarMaxValue(true);
  302.                     this.ShowBeginStep();

  303.                     foreach (TGZipFileEntry fileEntry in m_PacketEntryList)
  304.                     {
  305.                         this.SetProgressBarNowMaxValue(fileEntry, true);

  306.                         fileEntry.ReadEntryInfo(srcStream);  // 读当前项的日期、文件名信息
  307.                         this.ShowProgressStep();
  308.                         this.DecompressFile(srcStream, fileEntry);
  309.                         fileEntry.ResetFileDateTime(m_FolderDecompressTo);
  310.                     }
  311.                 }
  312.                 opSuccess = true;
  313.             }
  314.             catch (Exception err)
  315.             {
  316.                 throw new Exception(err.Message);
  317.             }
  318.             finally
  319.             {
  320.                 this.ShowFinalStep();
  321.                 this.SetApplicationCursor(Cursors.Default);
  322.             }

  323.             return opSuccess;
  324.         }

  325.         /// <summary>
  326.         /// Compress one file.
  327.         /// </summary>
  328.         private void CompressFile(TGZipFileEntry fileEntry, Stream outStream)
  329.         {
  330.             long preStreamPosition = outStream.Position;

  331.             using (FileStream srcStream = new FileStream(fileEntry.FileFullName, FileMode.Open, FileAccess.Read, FileShare.Read))
  332.             using (GZipStream zipStream = new GZipStream(outStream, CompressionMode.Compress, true))
  333.             {
  334.                 this.ShowProgressStep();

  335.                 int readCount = m_ReadBufferSize;
  336.                 while (readCount == m_ReadBufferSize)
  337.                 {
  338.                     readCount = srcStream.Read(m_ReadBuffer, 0, m_ReadBufferSize);
  339.                     zipStream.Write(m_ReadBuffer, 0, readCount);

  340.                     this.ShowProgressStep();
  341.                 }
  342.             }

  343.             fileEntry.GZipFileLength =  (int)(outStream.Position - preStreamPosition);  // 写入的长度
  344.         }

  345.         /// <summary>
  346.         /// Deompress one file.
  347.         /// </summary>
  348.         private void DecompressFile(Stream srcStream, TGZipFileEntry fileEntry)
  349.         {
  350.             using (FileStream outStream = new FileStream(this.m_FolderDecompressTo + fileEntry.FileName , FileMode.Create, FileAccess.Write, FileShare.None))
  351.             using (MemoryStream memStream = new MemoryStream())
  352.             using (GZipStream zipStream = new GZipStream(memStream, CompressionMode.Decompress, true))
  353.             {
  354.                 int gzipFileLength = fileEntry.GZipFileLength;
  355.                 int readCount;
  356.                 while (gzipFileLength > 0)
  357.                 {
  358.                     int maxCount = Math.Min(gzipFileLength, m_ReadBufferSize);
  359.                     
  360.                     readCount = srcStream.Read(m_ReadBuffer, 0, maxCount);
  361.                     memStream.Write(m_ReadBuffer, 0, readCount);

  362.                     gzipFileLength -= readCount;

  363.                     this.ShowProgressStep();
  364.                 }

  365.                 memStream.Position = 0;
  366.                 readCount = m_ReadBufferSize;
  367.                 while (readCount == m_ReadBufferSize)
  368.                 {
  369.                     readCount = zipStream.Read(m_ReadBuffer, 0, m_ReadBufferSize);
  370.                     outStream.Write(m_ReadBuffer, 0, readCount);

  371.                     this.ShowProgressStep();
  372.                 }
  373.             }
  374.             this.ShowProgressStep();
  375.         }

  376.         /// <summary>
  377.         /// 写空头字节, 用于占位置
  378.         /// </summary>
  379.         private void WriteHeaderEmptyInfo(Stream outStream)
  380.         {
  381.             int headerSize = 1 + m_FileEntryList.Count * 3;  // 前4个字节是文件数, 每个文件3部分, 分别是: 原文件长、压缩后长、文件项长
  382.             byte[] headerBytes = new byte[4 * headerSize];
  383.             outStream.Write(headerBytes, 0, headerBytes.Length);
  384.         }

  385.         /// <summary>
  386.         /// 写实际的文件数、文件长度、项长度字节
  387.         /// </summary>
  388.         private void WriteHeaderLengthInfo(Stream outStream)
  389.         {
  390.             byte[] fileCountBytes = BitConverter.GetBytes((int)m_PacketEntryList.Count);
  391.             TCipher.EncryptBytes(fileCountBytes);

  392.             outStream.Position = 0;
  393.             outStream.Write(fileCountBytes, 0, fileCountBytes.Length);

  394.             foreach (TGZipFileEntry entry in m_PacketEntryList)
  395.             {
  396.                 entry.WriteLengthInfo(outStream);
  397.             }
  398.         }

  399.         private void ReadHeaderLengthInfo(Stream srcStream)
  400.         {
  401.             byte[] fileCountBytes = new byte[4];
  402.             srcStream.Read(fileCountBytes, 0, fileCountBytes.Length);
  403.             TCipher.EncryptBytes(fileCountBytes);

  404.             int fileCount = BitConverter.ToInt32(fileCountBytes, 0);

  405.             for (int k = 1; k <= fileCount; k++)
  406.             {
  407.                 TGZipFileEntry entry = new TGZipFileEntry();
  408.                 entry.ReadLengthInfo(srcStream);
  409.                 m_PacketEntryList.Add(entry);
  410.             }
  411.         }

  412.         private bool GetPacketEntryList()
  413.         {
  414.             if (m_PacketEntryList.Count > 0)
  415.             {
  416.                 return true;
  417.             }

  418.             if (string.IsNullOrEmpty(m_GZipFileName) || !File.Exists(m_GZipFileName))
  419.             {
  420.                 MessageBox.Show("GZipFileName is empty or does not exist.");
  421.                 return false;
  422.             }

  423.             bool opSuccess = false;
  424.             this.SetApplicationCursor(Cursors.WaitCursor);

  425.             try
  426.             {
  427.                 using (FileStream srcStream = new FileStream(m_GZipFileName, FileMode.Open, FileAccess.Read, FileShare.Read))
  428.                 {
  429.                     this.ReadHeaderLengthInfo(srcStream);
  430.                     foreach (TGZipFileEntry fileEntry in m_PacketEntryList)
  431.                     {
  432.                         fileEntry.ReadEntryInfo(srcStream);
  433.                         srcStream.Position += fileEntry.GZipFileLength;
  434.                     }
  435.                 }
  436.                 opSuccess = true;
  437.             }
  438.             catch (Exception err)
  439.             {
  440.                 throw new Exception(err.Message);
  441.             }
  442.             finally
  443.             {
  444.                 this.SetApplicationCursor(Cursors.Default);
  445.             }
  446.             return opSuccess;
  447.         }

  448.         private int GetFileMaxStepLength(TGZipFileEntry fileEntry, bool decompress)
  449.         {
  450.             int maxLength = Math.Max(fileEntry.OriginalLength, fileEntry.GZipFileLength);
  451.             int stepValue = 0;

  452.             if (decompress)
  453.             {
  454.                 stepValue++;  // 取文件项
  455.                 stepValue += 2 * (maxLength / m_ReadBufferSize);  // 产生压缩流
  456.                 stepValue++;  // 关闭文件
  457.             }
  458.             else
  459.             {
  460.                 stepValue++;  // 打开源文件
  461.                 stepValue++;  // 写文件信息项
  462.                 stepValue += maxLength / m_ReadBufferSize;  // 压缩
  463.             }

  464.             return stepValue;
  465.         }

  466.         private void SetProgressBarMaxValue(bool decompress)
  467.         {
  468.             this.SetStartPosition();
  469.             m_NowMaxBarValue = 0;

  470.             int maxBarValue = 1;  // 打开/建立文件
  471.             if (decompress)
  472.             {
  473.                 foreach (TGZipFileEntry fileEntry in m_PacketEntryList)
  474.                 {
  475.                     maxBarValue += this.GetFileMaxStepLength(fileEntry, decompress);  // 加每个文件的步长
  476.                 }
  477.             }
  478.             else
  479.             {
  480.                 foreach (TGZipFileEntry fileEntry in m_FileEntryList)
  481.                 {
  482.                     maxBarValue += this.GetFileMaxStepLength(fileEntry, decompress);  // 加每个文件的步长
  483.                 }
  484.             }
  485.             maxBarValue += 1;  // 最后收尾
  486.             this.Maximum = maxBarValue;
  487.         }

  488.         private void SetProgressBarNowMaxValue(TGZipFileEntry fileEntry, bool decompress)
  489.         {
  490.             m_NowMaxBarValue += this.GetFileMaxStepLength(fileEntry, decompress);
  491.         }

  492.         /// <summary>
  493.         /// 设置当前控件及其全部父控件的光标
  494.         /// </summary>
  495.         private void SetApplicationCursor(Cursor cursor)
  496.         {
  497.             this.Cursor = cursor;
  498.             Control parent = this.Parent;
  499.             while (parent != null)
  500.             {
  501.                 parent.Cursor = cursor;
  502.                 parent = parent.Parent;
  503.             }
  504.         }

  505.         private void SetStartPosition()
  506.         {
  507.             this.Value = 0;
  508.             this.Refresh();
  509.         }

  510.         private void ShowBeginStep()
  511.         {
  512.             this.Value += 1;
  513.             this.Refresh();
  514.         }

  515.         private void ShowProgressStep()
  516.         {
  517.             if (this.Value + 1 < m_NowMaxBarValue)
  518.             {
  519.                 this.Value += 1;
  520.             }
  521.         }

  522.         private void ShowFinalStep()
  523.         {
  524.             while (this.Value + 1 < this.Maximum)
  525.             {
  526.                 this.Value += 1;
  527.             }
  528.             this.Value = this.Maximum;
  529.             this.Refresh();
  530.         }

  531.         private bool IsValidFileName(string fileName)
  532.         {
  533.             if (string.IsNullOrEmpty(fileName))
  534.             {
  535.                 return false;
  536.             }
  537.             else
  538.             {
  539.                 string realName = Path.GetFileName(fileName);
  540.                 string pathName = Path.GetDirectoryName(fileName);

  541.                 char[] errChars = Path.GetInvalidPathChars();
  542.                 if (realName.IndexOfAny(errChars) >= 0)
  543.                 {
  544.                     return false;
  545.                 }

  546.                 errChars = Path.GetInvalidPathChars();
  547.                 if (pathName.IndexOfAny(errChars) >= 0)
  548.                 {
  549.                     return false;
  550.                 }
  551.             }
  552.             return true;
  553.         }

  554.     }

  555.     /// <summary>
  556.     /// File entry class.
  557.     /// </summary>
  558.     public class TGZipFileEntry
  559.     {
  560.         private int m_OriginalLength;
  561.         private int m_GZipFileLength;
  562.         private int m_FileEntryLength;

  563.         private string m_FileFullName;

  564.         private DateTime m_CreationTime;
  565.         private DateTime m_LastAccessTime;
  566.         private DateTime m_LastWriteTime;

  567.         public TGZipFileEntry() { }

  568.         public TGZipFileEntry(string fileName)
  569.         {
  570.             FileInfo fileInfo = new FileInfo(fileName);

  571.             m_OriginalLength = (int)fileInfo.Length;
  572.             m_FileFullName = fileInfo.FullName;
  573.             m_CreationTime = fileInfo.CreationTime;
  574.             m_LastAccessTime = fileInfo.LastAccessTime;
  575.             m_LastWriteTime = fileInfo.LastWriteTime;
  576.         }

  577.         public int OriginalLength
  578.         {
  579.             get { return m_OriginalLength; }
  580.             set { m_OriginalLength = value; }
  581.         }

  582.         public int GZipFileLength
  583.         {
  584.             get { return m_GZipFileLength; }
  585.             set { m_GZipFileLength = value; }
  586.         }

  587.         public int FileEntryLength
  588.         {
  589.             get { return m_FileEntryLength; }
  590.             set { m_FileEntryLength = value; }
  591.         }

  592.         public void WriteLengthInfo(Stream outStream)
  593.         {
  594.             byte[] bytes1 = BitConverter.GetBytes(m_OriginalLength);
  595.             byte[] bytes2 = BitConverter.GetBytes(m_GZipFileLength);
  596.             byte[] bytes3 = BitConverter.GetBytes(m_FileEntryLength);

  597.             TCipher.EncryptBytes(bytes1);
  598.             TCipher.EncryptBytes(bytes2);
  599.             TCipher.EncryptBytes(bytes3);

  600.             outStream.Write(bytes1, 0, bytes1.Length);
  601.             outStream.Write(bytes2, 0, bytes2.Length);
  602.             outStream.Write(bytes3, 0, bytes3.Length);
  603.         }

  604.         public void ReadLengthInfo(Stream srcStream)
  605.         {
  606.             byte[] bytes1 = new byte[4];
  607.             byte[] bytes2 = new byte[4];
  608.             byte[] bytes3 = new byte[4];

  609.             srcStream.Read(bytes1, 0, bytes1.Length);
  610.             srcStream.Read(bytes2, 0, bytes2.Length);
  611.             srcStream.Read(bytes3, 0, bytes3.Length);

  612.             TCipher.EncryptBytes(bytes1);
  613.             TCipher.EncryptBytes(bytes2);
  614.             TCipher.EncryptBytes(bytes3);

  615.             m_OriginalLength = BitConverter.ToInt32(bytes1, 0);
  616.             m_GZipFileLength = BitConverter.ToInt32(bytes2, 0);
  617.             m_FileEntryLength = BitConverter.ToInt32(bytes3, 0);
  618.         }

  619.         public void WriteEntryInfo(Stream outStream)
  620.         {
  621.             byte[] entryBytes = this.GetFileEntryByes();
  622.             TCipher.EncryptBytes(entryBytes);
  623.             outStream.Write(entryBytes, 0, entryBytes.Length);  // 文件项内容

  624.             m_FileEntryLength = entryBytes.Length;
  625.         }

  626.         public void ReadEntryInfo(Stream srcStream)
  627.         {
  628.             byte[] entryBytes = new byte[m_FileEntryLength];
  629.             srcStream.Read(entryBytes, 0, entryBytes.Length);  // FileEntry 字节
  630.             TCipher.EncryptBytes(entryBytes);

  631.             string entryStr = Encoding.Default.GetString(entryBytes);  // 不能用 ASCII, 要处理汉字
  632.             string[] strArray = entryStr.Split('|');

  633.             long lastWriteTimeticks = long.Parse(strArray[3]);
  634.             long lastAccessTimeticks = long.Parse(strArray[4]);
  635.             long lastCreateTimeticks = long.Parse(strArray[5]);

  636.             m_LastWriteTime = new DateTime(lastWriteTimeticks);
  637.             m_LastAccessTime = new DateTime(lastAccessTimeticks);
  638.             m_CreationTime = new DateTime(lastCreateTimeticks);

  639.             m_FileFullName = strArray[6];
  640.         }

  641.         public void ResetFileDateTime(string folderCompressTo)
  642.         {
  643.             string fileName = folderCompressTo + Path.GetFileName(m_FileFullName);

  644.             File.SetLastAccessTime(fileName, m_LastAccessTime);
  645.             File.SetCreationTime(fileName, m_CreationTime);
  646.             File.SetLastWriteTime(fileName, m_LastWriteTime);
  647.         }

  648.         public string FormattedStr
  649.         {
  650.             get
  651.             {
  652.                 StringBuilder sb = new StringBuilder();

  653.                 sb.Append(Path.GetFileName(m_FileFullName));
  654.                 sb.Append("|" + m_OriginalLength.ToString());
  655.                 sb.Append("|" + m_GZipFileLength.ToString());
  656.                 sb.Append("|" + m_LastWriteTime.ToString("yyyy-MM-dd hh:mm:ss"));
  657.                 sb.Append("|" + m_LastAccessTime.ToString("yyyy-MM-dd hh:mm:ss"));
  658.                 sb.Append("|" + m_CreationTime.ToString("yyyy-MM-dd hh:mm:ss"));
  659.                 sb.Append("|" + m_FileFullName);

  660.                 return sb.ToString();
  661.             }
  662.         }

  663.         public string FileName
  664.         {
  665.             get { return Path.GetFileName(m_FileFullName); }
  666.         }

  667.         public string FileFullName
  668.         {
  669.             get { return m_FileFullName; }
  670.         }

  671.         private byte[] GetFileEntryByes()
  672.         {
  673.             StringBuilder sb = new StringBuilder();

  674.             sb.Append(Path.GetFileName(m_FileFullName));
  675.             sb.Append("|" + m_OriginalLength.ToString());
  676.             sb.Append("|" + m_GZipFileLength.ToString());
  677.             sb.Append("|" + m_LastWriteTime.Ticks.ToString());
  678.             sb.Append("|" + m_LastAccessTime.Ticks.ToString());
  679.             sb.Append("|" + m_CreationTime.Ticks.ToString());
  680.             sb.Append("|" + m_FileFullName);

  681.             string str = sb.ToString();
  682.             return Encoding.Default.GetBytes(str);  // 不能用 ASCII, 要处理汉字
  683.         }
  684.     }

  685.     /// <summary>
  686.     /// 简单加密类
  687.     /// </summary>
  688.     public class TCipher
  689.     {
  690.         private static readonly byte[] m_XORVector = new byte[] { 8, 3, 6, 1, 0, 9 };

  691.         public static void EncryptBytes(byte[] byteArray)
  692.         {
  693.             int k = 0;
  694.             for (int i = 0; i < byteArray.Length; i++)
  695.             {
  696.                 byteArray[i] ^= m_XORVector[k];
  697.                 k++;
  698.                 k = k % m_XORVector.Length;
  699.             }
  700.         }
  701.     }
  702. }


不用第三方控件,让richEdit支持图片与表格换行 DELPHI 6 提供的RICHEDIT是1.0,并不支持图片,对复杂表格也会乱成一团,如何在DELPHI原有控件的基础上做少量修改,使之支持显示图片与正确显示表格,其实只需要几行就好了,方法如下: 找到richEdit控件所在单元ComCtrls.pas (在SOURCE\VCL) //第一步 procedure TCustomRichEdit.CreateParams(var Params: TCreateParams); const // RichEditModuleName = 'RICHED32.DLL';//原来语句 // RichEditClassName = 'RICHEDIT'; //原来语句 RichEditModuleName = 'Msftedit.dll'; //改后语句 RichEditClassName = 'RichEdit50W'; //改后语句 //第二步 procedure TCustomRichEdit.CreateWnd; .... //加入一行要放在 CreateWnd 因为此时 HANDLE已建立 Perform(EM_SetOleCallback, 0, Longint(TRichEditOleCallback.Create(TRichEdit(self)) as IRichEditOleCallback)) ; //第三步 procedure TCustomRichEdit.WMRButtonUp(var Message: TWMRButtonUp); begin inherited; // RichEd20 does not pass the WM_RBUTTONUP message to defwndproc, // so we get no WM_CONTEXTMENU message. Simulate message here. // if Win32MajorVersion < 5 then //是原有1.0的要去掉 Perform(WM_CONTEXTMENU, Handle, LParam(PointToSmallPoint( ClientToScreen(SmallPointToPoint(Message.Pos))))); end; //第四步 procedure TRichEditStrings.Insert(Index: Integer; const S: string); .... //要去掉后面两名 // 1.0 uses, 2.0 will error happened 2011 // if RichEdit.SelStart (Selection.cpMax + Length(Str)) then //是原有1.0的要去掉 // raise EOutOfResources.Create(sRichEditInsertError); //是原有1.0的要去掉
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值