zoukankan      html  css  js  c++  java
  • [c#]自己制作类似winrar的打包程序(1)

         在好久以前,我就想写一个像暴雪的MPQ的文件结构,由于MPQ是不开源的,在网上找的资料又不是很全,像《MPQ技术内幕》只有那么一点,而且是C++,所以说令我很烦恼,但是捏,我在偶然间发现了一个很简单的文件结构,于是乎我就灵光一现,做了一个小的音乐播放器.....播放自己特有“格式”的音乐。

    利用了以下插件:

    /*
    ICSharpCode.SharpZipLib
    libzplay
    */
    

      目前为止可以实现用SharpZipLib来压缩/解压缩单个文件,用LibZPlay来播放OGG格式的文件(大家可以去google一下LibZPlay,灰常强大!)。首先,我们要有自己的文件结构,源码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO;
    using System.Runtime.Serialization.Formatters.Binary;
    namespace DSTFS
    {
        public class DSTFS
        {
            private PackFile _pf;
            private List<string> _pathList = new List<string>();
    
            #region 添加文件
            /// <summary>
            /// 添加文件
            /// </summary>
            /// <param name="source">要添加的文件的名字</param>
            public void AddSourceFile(string source)
            {
                if (File.Exists(source))
                    this._pathList.Add(source);
                else
                    throw new FileNotFoundException(source);
            }
            #endregion 添加文件
    
            #region 创建新文件
            /// <summary>
            /// 创建一个新文件
            /// </summary>
            /// <param name="path">要创建的文件完整路径</param>
            public void Build(string path)
            {
                using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write))
                {
                    BinaryWriter bw = new BinaryWriter(fs);
                    bw.Write("DST_PackFile_V1");
                    bw.Write(this._pathList.Count);
                    foreach (string f in this._pathList)
                    {
                        FileInfo fi = new FileInfo(f);
                        bw.Write(fi.Length);
                        fi = null;
                    }
                    foreach (string f in this._pathList)
                    {
                        bw.Write(Path.GetFileName(f));
                    }
                    foreach (string f in this._pathList)
                    {
                        bw.Write(File.ReadAllBytes(f));
                        bw.Flush();
                    }
                }
            }
            #endregion 创建新文件
    
            #region 读取文件
            /// <summary>
            /// 读取文件
            /// </summary>
            /// <param name="path">要读取的文件的完整路径</param>
            public void LoadPackFile(string path)
            {
                if (!File.Exists(path))
                {
                    throw new FileNotFoundException(path);
                }
                if (_pf != null)
                {
                    _pf.Close();
                    _pf = null;
                }
                FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
                BinaryReader br = new BinaryReader(fs);
                if (br.ReadString() != "DST_PackFile_V1")
                {
                    throw new InvalidCoalescentFileException("该文件不是有效的包文件");
                }
                this._pf = new PackFile(fs, br);
            }
            #endregion 读取文件
    
            #region Properties
            /// <summary>
            /// Properties
            /// </summary>
            public PackFile CurrentPackFile
            {
                get
                {
                    return this._pf;
                }
            }
            #endregion Properties
        }
    
        /// <summary>
        /// 文件部分
        /// </summary>
        public class PackFile
        {
    
            private FileStream _sourceFile;
            private BinaryReader _br;
            private long _contentStartPos;
            private int _fileCount;
            private List<long> _fileLengthList = new List<long>();
            private List<string> _shortNameList = new List<string>();
    
            internal PackFile(FileStream srcFile, BinaryReader br)
            {
                this._sourceFile = srcFile;
                _br = br;
                this._fileCount = _br.ReadInt32();//取文件数
    
                for (int i = 1; i <= _fileCount; i++)
                {
                    this._fileLengthList.Add(_br.ReadInt64());
                }
    
                for (int i = 1; i <= _fileCount; i++)
                {
                    this._shortNameList.Add(_br.ReadString());
                }
                this._contentStartPos = _sourceFile.Position;//设置实体文件内容的起始位置
    
            }
    
            public MemoryStream GetStream(int index)
            {
                return new MemoryStream(GetBytes(index));
            }
    
            public byte[] GetBytes(int index)
            {
                long startPos = this._contentStartPos;
    
                for (int i = 0; i < index; i++)
                {
                    startPos += this._fileLengthList[i];
                }
    
                _sourceFile.Position = startPos;
                return _br.ReadBytes((int)_fileLengthList[index]);
            }
    
            public void OutputAllToDirectory(string dir)
            {
                if (!Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }
    
                for (int i = 0; i < _fileCount; i++)
                {
                    File.WriteAllBytes(dir + this._shortNameList[i], GetBytes(i));
                }
            }
    
            /// <summary>
            /// 以新名字输出某个内容到文件
            /// </summary>
            /// <param name="index"></param>
            /// <param name="file"></param>
            public void OutputOneToFile(int index, string file)
            {
                File.WriteAllBytes(file, GetBytes(index));
            }
    
            /// <summary>
            /// 用原始文件名输出某个内容到指定文件夹
            /// </summary>
            /// <param name="index"></param>
            /// <param name="dir"></param>
            public void OutputOneToDirectory(int index, string dir)
            {
                string name = _shortNameList[index];
                File.WriteAllBytes(Path.Combine(dir, name), GetBytes(index));
            }
    
            internal void Close()
            {
                if (_sourceFile != null)
                {
                    _br.Close();
                    _br = null;
                    _sourceFile.Close();
                    _sourceFile = null;
                }
            }
    
            #region 属性
            //源包文件
            public string CurrentPackFile
            {
                get
                {
                    return this._sourceFile.Name;
                }
            }
    
            public int FileCount
            {
                get
                {
                    return this._fileCount;
                }
            }
    
    
            public string[] NameList
            {
                get
                {
                    return this._shortNameList.ToArray();
                }
            }
            #endregion
        }
    
        public class InvalidCoalescentFileException : Exception
        {
            public InvalidCoalescentFileException(string text)
                : base(text)
            {
            }
        }
    }
    

      

    好了,我们就可以用这个结构来创造自己独特的文件格式了。

    现在我们新建一个项目,引用这个类,首先在全局声明一个对象:

    DSTPackFile.DSTPF dst = new DSTPackFile.DSTPF();
    

      用以下代码创建一个文件:

    dst.AddSourceFile("1.ogg");
    dst.Build(textBox3.Text);
    //添加多个文件的话需要多次添加SourceFile,最后执行Build。
    

      好了,我们现在有一个灰常特殊的音乐文件了,那么肿么播放捏?我们用LibZPlay来实现播放功能。但是,首先我们要把文件中的音乐读出来:

    DSTPackFile.DSTPF dst = new DSTPackFile.DSTPF();
    dst.LoadPackFile("c:\\1.DST");
    var cf = dst.CurrentPackFile;
    var ms = dst.CurrentPackFile.GetStream(0);
    //我想把这个方法增加一个重载,不用数字编号了,直接用文件名就类似GetStream("1.ogg")一样,还在努力实现中....
    

      因为我们把音乐读取到内存当中了,所以我们就用流的方式播放:

    libZPlay.ZPlay player = new ZPlay();
    
                long numBytes = ms.Length;
                System.IO.BinaryReader br = new System.IO.BinaryReader(ms);
                byte[] stream_data = null;
                stream_data = br.ReadBytes(System.Convert.ToInt32((int)(numBytes)));
                if (!(player.OpenStream(true, false, ref stream_data, System.Convert.ToUInt32(numBytes), TStreamFormat.sfOgg)))
                {
                    MessageBox.Show(player.GetError(), string.Empty, MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                player.StartPlayback();
                br.Close();
    

      

    好了,我们就能听到音乐了。

    说实话,播放流的这段代码是我google来的,因为头一次用LibZPlay,所以一直播放不了用SharpZipLib压缩过的文件,我已经解压缩到内存里了,但是就是播放不了,所以没用到压缩。

    到现在我有一个设想:

    1.这个文件结构只是最简单的,我想它不光能打包文件,还能把文件夹打包进去。

    2.能用流的方式读出包文件里的东西,而且不需要太大的内存。

    3.能实现压缩功能(在不借助第三方插件),把声音、图片等等的文件有单独的压缩算法,并且解压的时候不是很费时。

    4.。。。。。。。。

    其实还有好多....只是现在想不起来了,等有新进展再接着写。要是各位大牛有神马批评、指导。请PM我~~

  • 相关阅读:
    php大文件分片上传
    ckeditor粘贴上传图片
    视频断点续传+java视频
    php上传文件夹 ​
    批量下载
    PHP上传超大文件解决方案
    js大文件上传
    java+web文件的上传和下载代码
    Webupload+PHP上传大文件
    【hdu1280】前M大的数
  • 原文地址:https://www.cnblogs.com/Hsppl/p/CSharp_PackFile_1.html
Copyright © 2011-2022 走看看