这篇文章介绍了
Net实现合并文件的具体方法
有需要的朋友可以参考一下
以上列表中的文件并不是来自于某个文件夹中的所有jpg文件而是来自于
这个文件
将多个文件合并为一个文件在许多应用领域都十分有用亲自实现这样一个程序一定不但过瘾且在许多时候可以帮助我们构建更高效的程序这里我做了一个方案例分享给大家
由于合并后的文件就像一个包裹所以下文中都把这样的文件称为“包文件”
主构思
要把多个文件合并成一个包文件还要可以区分其中的某个文件并提取出来我们需要知道文件的名称和这个文件在包文件中的位置及长度也就是所谓的地址偏移
由于包文件常常会比较大所以不应该让它的内容常驻于内存只应该需要某部分的时候再从包文件中提取
我是这样做的
一个管理器类提供一些外围的方法
_pathList用于存放要添加到包文件的文件路径通过调用AddSourceFile()方法添加
_pf 是具体的包文件通过LoadPackFile() 生成实例通过CurrentPackFile属性返回
Build方法用于生成包文件
PackFile类作为PackFileManager的嵌套类它提供包文件的属性和施工细节
好了我们先来看看PackFileManagerBuild()方法
复制代码 代码如下:
public void Build(string path)
{
using (FileStream fs = new FileStream(path
FileMode
Create
FileAccess
Write))
{
BinaryWriter bw = new BinaryWriter(fs);
bw
Write("PackFile");
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();
}
}
}
. 先写个“PackFile”字符串到文件头
. 把以Int为类型的要输出到包文件中的文件数量写入
. 把以long为类型的要输出到包文件中的每个文件的长度写入
. 再把每个文件名写入
. 最后写入每个文件的实体内容
由于在写或读时不频繁在Write方法或ReadXXX方法的不同版本间频繁切换所以我想这样组织文件结构可以更高效一些
疑问来了在写入文件名的时候我们使用bwWrite(PathGetFileName(f));
调用了 BinaryWriterWrite(string value)传入的是字符串那么在读取的时候要调用BinaryReaderReadString()这时它是如何区分两个字符串边界的还 好Write方法会先将字符串长度作为一个四字节无符号整数写入于是在用BinaryReaderReadString()的时候它会根据这个值来 读取特定长度的值并理解为字符串
这里列出几个重要方法
复制代码 代码如下:
PackFileManager的LoadPackFile方法
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() != "PackFile")
{
throw new InvalidCoalescentFileException("该文件不是有效的包文件");
}
this
_pf = new PackFile(fs
br);
}
此时我们在生成时写入的字符串"PackFile" 就有了明确的功能
PackFile的构造函数
复制代码 代码如下:
internal PackFile(FileStream srcFile
BinaryReader br)
{
this
_sourceFile = srcFile;
_br = br;
this
_fileCount = _br
ReadInt
();//取文件数
for (int i =
; i <= _fileCount; i++)
{
this
_fileLengthList
Add(_br
ReadInt
());
}
for (int i =
; i <= _fileCount; i++)
{
this
_shortNameList
Add(_br
ReadString());
}
this
_contentStartPos = _sourceFile
Position;//设置实体文件总起始位置
}
PackFileGetBytes()
复制代码 代码如下:
public byte[] GetBytes(int index)
{
long startPos = this
_contentStartPos;
for (int i =
; i < index; i++)
{
startPos += this
_fileLengthList[i];
}
_sourceFile
Position = startPos; //设置某文件内容的起始位置
return _br
ReadBytes((int)_fileLengthList[index]);
}
这只是一个草案我们还可以加入压缩或是像ZIP文件那样的嵌套文件夹功能改进后的代码别忘与我分享哦