Click here to Skip to main content
15,881,967 members
Articles / Programming Languages / C#

Project Tool

Rate me:
Please Sign up or sign in to vote.
4.69/5 (10 votes)
23 Sep 2007CPOL3 min read 54.5K   1.7K   73  
Backup your C# solution and projects for archive or source code sharing. Temporary or unused files are excluded.
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace QiHe.CodeLib.Compress
{
    /// <summary>
    /// zip archive file.
    /// Multi disk, encryption and Zip64 are not supported.
    /// </summary>
    public class ZipArchive
    {
        public string ZipFile;
        public Dictionary<string, ZipEntry> Entries = new Dictionary<string, ZipEntry>();

        public ZipArchive() { }

        bool isDifferentialArchive = false;
        DateTime BaseDateTime = DateTime.MinValue;
        public ZipArchive(DateTime baseDateTime)
        {
            isDifferentialArchive = true;
            BaseDateTime = baseDateTime;
        }

        public IEnumerable<string> Files
        {
            get { return Entries.Keys; }
        }

        /// <summary>
        /// file comment length
        /// </summary>
        UInt16 FileCommentLength = 0;
        byte[] FileCommentBytes;

        public string Comment
        {
            get
            {
                return ZipFormat.TextEncoding.GetString(FileCommentBytes);
            }
            set
            {
                FileCommentBytes = ZipFormat.TextEncoding.GetBytes(value);
                FileCommentLength = (UInt16)FileCommentBytes.Length;
            }
        }

        public void Add(string basePath, string relativePath)
        {
            ZipEntry zipEntry = new ZipEntry();
            zipEntry.FilePath = Path.Combine(basePath, relativePath);
            zipEntry.FileName = relativePath;
            if (File.Exists(zipEntry.FilePath))
            {
                zipEntry.ModifiedTime = File.GetLastWriteTime(zipEntry.FilePath);
                zipEntry.CompressMethod = (ushort)CompressionMethod.Deflate;
                if (isDifferentialArchive && zipEntry.ModifiedTime <= BaseDateTime)
                {
                    return;
                }
            }
            else if (Directory.Exists(zipEntry.FilePath))
            {
                zipEntry.ModifiedTime = Directory.GetLastWriteTime(zipEntry.FilePath);
                zipEntry.IsFile = false;
            }
            else
            {
                //throw new FileNotFoundException(zipEntry.FilePath);
                return; //skip
            }
            Entries[zipEntry.FileName] = zipEntry;
        }

        public void Save(string destfile)
        {
            using (FileStream output = File.Create(destfile))
            {
                WriteLocalFiles(output);
                BinaryWriter writer = new BinaryWriter(output);
                WriteCentralDirectory(writer);
                WriteCentralDirectoryEnd(writer);
                writer.Flush();
            }
        }

        public static ZipArchive Load(string zipfile)
        {
            ZipArchive archive = new ZipArchive();
            archive.ZipFile = zipfile;
            using (FileStream input = File.OpenRead(zipfile))
            {
                BinaryReader reader = new BinaryReader(input);
                while (true)
                {
                    try
                    {
                        ZipEntry zipEntry = new ZipEntry();
                        zipEntry.ReadLocalHeader(reader);
                        archive.Entries[zipEntry.FileName] = zipEntry;
                        reader.BaseStream.Position += zipEntry.CompressedSize;
                    }
                    catch
                    {
                        break;
                    }
                }
            }
            return archive;
        }

        public void Extract(string file, string destdir)
        {
            using (FileStream input = File.OpenRead(ZipFile))
            {
                string destfile = Path.Combine(destdir, file);
                ZipEntry entry = Entries[file];
                entry.FilePath = destfile;
                entry.IsFile = !destfile.EndsWith("/");
                entry.Decompress(input);
            }
        }

        private void WriteLocalFiles(FileStream output)
        {
            foreach (ZipEntry entry in Entries.Values)
            {
                entry.Compress(output);
            }
        }

        private void WriteDigitalSignature(BinaryWriter writer)
        {
            writer.Write(ZipFormat.SignatureHeaderSignature);
            //to be implemented
        }

        long CentralDirectoryOffset;
        long CentralDirectorySize;
        private void WriteCentralDirectory(BinaryWriter writer)
        {
            CentralDirectoryOffset = writer.BaseStream.Position;
            foreach (ZipEntry entry in Entries.Values)
            {
                entry.WriteCentralHeader(writer);
            }
            //WriteDigitalSignature(writer);
            CentralDirectorySize = writer.BaseStream.Position - CentralDirectoryOffset;
        }

        private void WriteCentralDirectoryEnd(BinaryWriter writer)
        {
            writer.Write(ZipFormat.CentralDirectorySignature);
            writer.Write((UInt16)0); //number of this disk
            writer.Write((UInt16)0); //number of the disk with the start of the central directory
            writer.Write((UInt16)Entries.Count); //total number of entries in the central directory on this disk
            writer.Write((UInt16)Entries.Count); //total number of entries in the central directory
            writer.Write((UInt32)CentralDirectorySize); //size of the central directory
            writer.Write((UInt32)CentralDirectoryOffset); //offset of start of central directory with respect to the starting disk number
            writer.Write((UInt16)FileCommentLength); //.ZIP file comment length
            if (FileCommentLength > 0)
            {
                writer.Write(FileCommentBytes); //.ZIP file comment
            }
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect YunCheDa Hangzhou
China China
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions