文件的合并无非就是用流把所有的文件都写到同一个文件里。但有时候遇到大文件的时候,会出现内存溢出等情况,为了解决这个问题,我们可以考虑分段循环来读写文件。(目前测试的最大文件是4.8G)
下面我写说说合并文件的原理:首先是用一个文本文件来记录文件的目录结构(无论你文件夹有多少个层级目录,还原时有了它问题就简单了很多),最后把这个文件和要合并的文件一同写到大文件里面。
拆分的原理:先读出记录目录结构的文件,然后先循环创建文件夹。之后再一个一个还原文件。
接下来,我把代码贴出来供大家参考参考:
下面我写说说合并文件的原理:首先是用一个文本文件来记录文件的目录结构(无论你文件夹有多少个层级目录,还原时有了它问题就简单了很多),最后把这个文件和要合并的文件一同写到大文件里面。
拆分的原理:先读出记录目录结构的文件,然后先循环创建文件夹。之后再一个一个还原文件。
接下来,我把代码贴出来供大家参考参考:
Common.SaveFilePath //表示的是记录层级目录的文件
/// <summary> /// 初始化层级目录文件 /// </summary> private void CreateInit() { //每次合并文件前保证这个文件是不存在的,以免目录结构混乱 if (File.Exists(Common.SaveFilePath)) { File.Delete(Common.SaveFilePath); } if (!File.Exists(Common.SaveFilePath)) { using (FileStream fs = File.Create(Common.SaveFilePath)) { Byte[] info = new UTF8Encoding(true).GetBytes(""); fs.Write(info, 0, info.Length); } } } /// <summary> /// 记录文件夹的层级关系 /// </summary> /// <param name="path">要合并的文件夹或文件路径</param> private void GetRecord(string path) { try { if (Directory.Exists(path)) { string[] wang = Directory.GetFiles(path); for (int j = 0; j < wang.ToList().Count; j++) { using (FileStream fs = File.Open(Common.SaveFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) { //如果不执行一下,就总是一条数据,执行一下,就能顺序添加 byte[] b = new byte[1024]; UTF8Encoding temp = new UTF8Encoding(true); while (fs.Read(b, 0, b.Length) > 0) { fs.Flush(); } Byte[] info = new UTF8Encoding(true).GetBytes(wang[j] + '\r' + '\n'); fs.Write(info, 0, info.Length); } } string[] kid = Directory.GetDirectories(path);//选择文件夹下的子文件夹 for (int i = 0; i < kid.ToList().Count; i++) { using (FileStream fs = File.Open(Common.SaveFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) { //如果不执行一下,就总是一条数据,执行一下,就能顺序添加 byte[] b = new byte[1024]; UTF8Encoding temp = new UTF8Encoding(true); while (fs.Read(b, 0, b.Length) > 0) { fs.Flush(); } Byte[] info = new UTF8Encoding(true).GetBytes(kid[i] + '\r' + '\n'); fs.Write(info, 0, info.Length); fs.Close(); GetRecord(kid[i]); } } } else { using (FileStream fs = File.Open(Common.SaveFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) { Byte[] info = new UTF8Encoding(true).GetBytes(path + '\r' + '\n'); //如果不执行一下,就总是一条数据,执行一下,就能顺序添加 byte[] b = new byte[info.Length]; UTF8Encoding temp = new UTF8Encoding(true); while (fs.Read(b, 0, b.Length) > 0) { fs.Flush(); } fs.Write(info, 0, info.Length); } } } catch (Exception) { MessageBox.Show(@"层级目录没有生成"); } } /// <summary> /// 合并其中内容(包含文件) /// </summary> private void UnionFile() { int counter = 0; string line; string[] file_names;//里面存放的是所有文件的路径包括文件名 using (StreamReader file = new StreamReader(Common.SaveFilePath)) { while ((line = file.ReadLine()) != null) { //判断是文件夹还是文件 FileInfo fileInfo = new FileInfo(line); if ((fileInfo.Attributes & FileAttributes.Directory) == 0)//文件 { counter++; } } file_names = new string[counter + 1];//索引值必须比加密文件夹下的所有文件个数相加多一个才可以,因为要考虑到添加的那个层级目录文件 } using (StreamReader file = new StreamReader(Common.SaveFilePath)) { int okb = 0; while ((line = file.ReadLine()) != null) { //判断是文件夹还是文件 string savefile = line.Substring(line.IndexOf("|") + 1); FileInfo fileInfo = new FileInfo(savefile); if ((fileInfo.Attributes & FileAttributes.Directory) == 0) { file_names.SetValue(savefile, ++okb); } } file_names.SetValue(Common.SaveFilePath, 0); //////到此文件合并的准备工作完成,接下来开始文件的合并 Packer.Pack(Common.TmpFilePath, file_names);//文件打包 } } public class Header { public long Length; public string Filename; /// <summary> /// 向合并之后的文件写入每个文件的名称和长度 /// </summary> /// <param name="fs"></param> public void WriteTo(Stream fs) { byte[] len = BitConverter.GetBytes(Length); byte[] buf = new byte[24680];//如果文件名太长,必须扩大数组范围 byte[] str = Encoding.Unicode.GetBytes(Filename); str.CopyTo(buf, 0); fs.Write(len, 0, len.Length); fs.Write(buf, 0, buf.Length); } /// <summary> /// 从大文件中读取单文件的长度和名称 /// </summary> /// <param name="fs"></param> /// <returns></returns> public bool ReadFrom(Stream fs) { byte[] len = BitConverter.GetBytes(Length); byte[] buf = new byte[24680];//如果文件名太长,必须扩大数组范围 if (len.Length != fs.Read(len, 0, len.Length)) return false; if (buf.Length != fs.Read(buf, 0, buf.Length)) return false; Length = BitConverter.ToInt64(len, 0); Filename = Encoding.Unicode.GetString(buf).Trim(new char[] { '\0' }); return true; } } public class Packer { /// <summary> /// 文件打包 /// </summary> /// <param name="resultFilename">要打包的文件或文件夹</param> /// <param name="filenames">所有文件的路径包括文件名</param> public static void Pack(string resultFilename, params string[] filenames) { using (FileStream fout = new FileStream(resultFilename, FileMode.Create, FileAccess.Write)) { for (int i = 0; i < filenames.Length; i++) { using (FileStream fin = new FileStream(filenames[i], FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { Header header = new Header(); header.Length = fin.Length; //header.filename = Path.GetFileName(filenames[i]); header.Filename = filenames[i]; header.WriteTo(fout); byte[] buf; if (header.Length > 1024 * 1024 * 32) { buf = new byte[1024 * 1024 * 32]; } else { buf = new byte[header.Length]; } BinaryReader br = new BinaryReader(fin); BinaryWriter bw = new BinaryWriter(fout); while (fin.Position < fin.Length) { int readCount = br.Read(buf, 0, buf.Length); bw.Write(buf, 0, readCount); } } } } } /// <summary> /// 拆分文件 /// </summary> /// <param name="filename">要拆分的文件路径</param> public static void Unpack(string filename) { using (FileStream fin = new FileStream(filename, FileMode.Open, FileAccess.Read)) { Header header = new Header(); int counter = 0; string line; while (header.ReadFrom(fin)) { unpackedFiles.Add(header.Filename); byte[] buf; buf = new byte[1024 * 1024 * 32]; long num = header.Length / (1024 * 1024 * 32); long slack = header.Length % (1024 * 1024 * 32); BinaryReader br = new BinaryReader(fin); using (FileStream fout = new FileStream(header.Filename, FileMode.Create, FileAccess.Write)) { BinaryWriter bw = new BinaryWriter(fout); for (int j = 0; j < num; j++) { int readCount = br.Read(buf, 0, buf.Length); bw.Write(buf, 0, readCount); } if (slack > 0) { int readCount = br.Read(buf, 0, (int)slack); bw.Write(buf, 0, readCount); } bw.Flush(); } //解压出第一个文件时,该文件就是层级目录,要按照层级目录,创建文件夹,这样,那些文件才会有归属 if (counter == 0) { using (StreamReader file = new StreamReader(Common.SaveFilePath)) { while ((line = file.ReadLine()) != null) { //判断是文件夹还是文件 FileInfo fileInfo = new FileInfo(line); if ((fileInfo.Attributes & FileAttributes.Directory) != 0) { if (fileInfo.DirectoryName != null) { Directory.CreateDirectory(fileInfo.DirectoryName); } } } } counter = 1; } } } } }
接下来调用以上方法试试:
合并:
CreateInit();
GetRecord(path); //生成层级目录 path
表示您要合并的文件或文件夹路径
UnionFile();//合并文件
File.Delete(Common.SaveFilePath); //合并完后将记录层级目录的文件删除
拆分:
Packer.Unpack(path);//path 表示您要拆分的文件路径
想要完整的demo的话 ,在下一篇文件加解密最下面附有下载地址