将文件打包成一个,以便以后以编程方式解压缩它们

时间:2014-02-01 06:55:43

标签: c# packaging

是否可以将目录中的所有文件和文件夹打包并打包到单个包文件中,以便我可以通过网络传输此包,然后从包中解压缩所有文件和文件夹?

我尝试用C#查看ZIP文件,因为我的目标是相同的想法,但实际的方法只有.NET 3.5(我相信),我也希望程序非常轻量级,意思是如果我想解压缩/解压缩单个文件,我不希望外围的模块位于其中。

我该如何做到这一点?

3 个答案:

答案 0 :(得分:5)

只需使用BinaryWriter / Reader和您自己的格式。像这样:

using (var fs = File.Create(...))
using (var bw = new BinaryWriter(fs))
{
    foreach (var file in Directory.GetFiles(...))
    {
        bw.Write(true); // means that a file will follow
        bw.Write(Path.GetFileName(file));
        var data = File.ReadAllBytes(file);
        bw.Write(data.Length);
        bw.Write(data);
    }
    bw.Write(false); // means end of file
}

所以基本上你写一个bool意味着是否有下一个文件,每个文件的名称和内容,一个接一个。阅读恰恰相反。 BinaryWriter / Reader会处理所有事情(它知道每个字符串和字节数组有多长,你会准确地读回你写的内容)。

此解决方案缺少的内容:不是行业标准(但非常简单),不存储任何其他元数据(可以添加创建时间等),不使用校验和(可以在之后添加SHA1哈希)内容),不使用压缩(你说你不需要它),不能很好地处理大文件(有问题的部分是它将整个文件读入一个字节数组并写入,应该工作得很好低于100 MB),不处理多级目录层次结构(当然可以添加)。

编辑:BinaryR / W知道字符串长度,但不知道字节数组的长度。我在字节数组之前添加了一个长度字段,以便可以在写入时完全回读它。

答案 1 :(得分:1)

查看 ziplib ,它是免费的,开源的,可以在所有.NET版本中使用:http://www.icsharpcode.net/opensource/sharpziplib/

答案 2 :(得分:0)

我建议你考虑使用外部库所带来的好处,这样你就可以忘记很多麻烦。拉链复杂类可能是一个巨大的交易。看一看:http://dotnetzip.codeplex.com/它简单,稳定,轻盈。

顺便说一句,如果你完全不想要外部库并且数据压缩对你的项目来说不是强制性的,你可以用这样的方式管理它(请把它当作一个用lees写的样本,而不是一个小时;-) ):

用法:

//to pack
Packer.SimplePack sp = new Packer.SimplePack(@"c:\filename.pack");
sp.PackFolderContent(@"c:\yourfolder");
sp.Save();

//to unpack
Packer.SimplePack sp = new Packer.SimplePack(@"c:\filename.pack");
sp.Open();

这是SimplePack:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Packer
{
    public class SimplePack
    {
        public class Header
        {
            public Int32 TotalEntries { get; set; }
            public Int64[] EntriesSize
            {
                get
                {
                    return EntriesSizeList.ToArray();
                }
            }
            private List<Int64> EntriesSizeList { get; set; }

            public Header()
            {
                TotalEntries = 0;
                EntriesSizeList = new List<Int64>();
            }

            public void AddEntrySize(Int64 newSize)
            {
                EntriesSizeList.Add(newSize);
            }
        }

        public class Item
        {
            public Byte[] RawData { get; set; }
            public String Name { get; set; }
            public String RelativeUri { get; set; }

            public Int64 ItemSize
            {
                get
                {
                    Int64 retVal = 4; //Name.Lenght;
                    retVal += Name.Length;
                    retVal += 4; //RelativeUri.Length
                    retVal += RelativeUri.Length;
                    retVal += RawData.Length;

                    return retVal;
                }
            }

            public Byte[] SerializedData
            {
                get
                {
                    List<Byte> retVal = new List<Byte>();
                    retVal.AddRange(BitConverter.GetBytes(Name.Length));
                    retVal.AddRange(Encoding.Default.GetBytes(Name));
                    retVal.AddRange(BitConverter.GetBytes(RelativeUri.Length));
                    retVal.AddRange(Encoding.Default.GetBytes(RelativeUri));
                    retVal.AddRange(RawData);
                    return retVal.ToArray();
                }
            }

            public Item()
            {
                RawData = new Byte[0];
                Name = String.Empty;
                RelativeUri = String.Empty;
            }
            public Item(Byte[] serializedItem)
            {
                Int32 cursor = 0;
                Int32 nl = BitConverter.ToInt32(serializedItem, cursor);
                cursor += 4;
                Name = Encoding.Default.GetString(serializedItem, cursor, nl);
                cursor += nl;
                Int32 rl = BitConverter.ToInt32(serializedItem, cursor);
                cursor += 4;
                RelativeUri = Encoding.Default.GetString(serializedItem, cursor, rl);
                cursor += rl;
                RawData = new Byte[serializedItem.Length - cursor];
                for (int i = cursor; i < serializedItem.Length; i++)
                {
                    RawData[i - cursor] = serializedItem[cursor];
                }
            }
        }

        public FileInfo PackedFile { get; private set; }
        public List<Item> Data { get; private set; }

        public Header FileHeaderDefinition { get; private set; }

        public SimplePack(String fileName)
        {
            PackedFile = new FileInfo(fileName);
            FileHeaderDefinition = new Header();
            Data = new List<Item>();
        }

        public Boolean PackFolderContent(String folderFullName)
        {
            Boolean retVal = false;

            DirectoryInfo di = new DirectoryInfo(folderFullName);

            //Think about setting up strong checks and errors trapping

            if (di.Exists)
            {
                FileInfo[] files = di.GetFiles("*", SearchOption.AllDirectories);
                foreach (FileInfo fi in files)
                {
                    Item it = setItem(fi, di.FullName);
                    if (it != null)
                    {
                        Data.Add(it);
                        FileHeaderDefinition.TotalEntries++;
                        FileHeaderDefinition.AddEntrySize(it.ItemSize);
                    }
                }
            }
            //althoug it isn't checked
            retVal = true;

            return retVal;
        }

        private Item setItem(FileInfo sourceFile, String packedRoot)
        {
            if (sourceFile.Exists)
            {
                Item retVal = new Item();
                retVal.Name = sourceFile.Name;
                retVal.RelativeUri = sourceFile.FullName.Substring(packedRoot.Length).Replace("\\", "/");
                retVal.RawData = File.ReadAllBytes(sourceFile.FullName);
                return retVal;
            }
            else
            {
                return null;
            }
        }

        public void Save()
        {
            if (PackedFile.Exists)
            {
                PackedFile.Delete();
                System.Threading.Thread.Sleep(100);
            }
            using (FileStream fs = new FileStream(PackedFile.FullName, FileMode.CreateNew, FileAccess.Write))
            {
                //Writing Header
                //4 bytes
                fs.Write(BitConverter.GetBytes(FileHeaderDefinition.TotalEntries), 0, 4);
                //8 bytes foreach size
                foreach (Int64 size in FileHeaderDefinition.EntriesSize)
                {
                    fs.Write(BitConverter.GetBytes(size), 0, 8);
                }
                foreach (Item it in Data)
                {
                    fs.Write(it.SerializedData, 0, it.SerializedData.Length);
                }

                fs.Close();
            }
        }

        public void Open()
        {
            if (PackedFile.Exists)
            {
                using (FileStream fs = new FileStream(PackedFile.FullName, FileMode.Open, FileAccess.Read))
                {
                    Byte[] readBuffer = new Byte[4];
                    fs.Read(readBuffer, 0, readBuffer.Length);
                    FileHeaderDefinition.TotalEntries = BitConverter.ToInt32(readBuffer, 0);
                    for (Int32 i = 0; i < FileHeaderDefinition.TotalEntries; i++)
                    {
                        readBuffer = new Byte[8];
                        fs.Read(readBuffer, 0, readBuffer.Length);
                        FileHeaderDefinition.AddEntrySize(BitConverter.ToInt64(readBuffer, 0));
                    }

                    foreach (Int64 size in FileHeaderDefinition.EntriesSize)
                    {
                        readBuffer = new Byte[size];
                        fs.Read(readBuffer, 0, readBuffer.Length);
                        Data.Add(new Item(readBuffer));
                    }

                    fs.Close();
                }
            }
        }




    }
}