首页 > 其他 > 详细

文件打包学习1

时间:2019-11-24 20:00:21      阅读:84      评论:0      收藏:0      [点我收藏+]

打包的定义

??什么是打包?打包这个词很形象,就是把零碎的文件进行统一重封装,统一管理,比如我们常见的RAR文件,ZIP文件都是很常见的包裹格式

打包的意义

  1. 比如RAR包,我们虽然能有工具解压,但是我们却基本上没有相关的SDK来做二次开发
  2. ZIP包虽然有SDK来读取,但是对于通用的文件格式,我们无法做到保护资源的需求
  3. 如果只是为了文件管理的方便,无所谓别人解开资源的话,直接用现成的ZIP开发的SDK即可

打包的方式

  • 分类打包
    比如图片资源打一个包,声音资源打一个包
  • 全部打包
    把所有资源一起打包

打包的一般准则和规范

  1. 原始文件的标识,这个标识可以使原始文件名+路径名,或者也可以是转换后的数据如ID等,先从最简单的说起,使用原始文件名+路径名
  2. 原始文件的大小,把文件打进包裹之后,我们要知道这个原始文件有多大
  3. 原始文件的数据打包在包裹的什么位置

打包程序的实现框架

  1. 包裹文件的定义
  2. 添加CreatPackage(创建空白包裹)函数、AddFileToPackage(添加一个文件到包裹)函数
  3. CreatePackage(创建空白包裹)函数的实现
  4. AddFileToPackage(添加一个文件到包裹)函数的实现

package.h

#pragma once
#include <vector>

//先从最简单最简单的开始,以ASCII编码为准
struct PackageItem
{
    char            FileName[256];      //假设文件名定长,不超过256字符
    int             FileSize;           //假设文件不超过2G
    unsigned int    OffsetPackage;      //在包裹的偏移,同样最简单的演示我们假设包裹文件不大于4G
};



class CPackage
{
public:
    CPackage(void);
public:
    ~CPackage(void);

    bool CreatePackage( const char*szPackageName );     //创建一个空白包裹

    bool AddFileToPackage( const char*szFileName );     //添加一个文件到包裹
private:
    FILE                                *m_fpPackage;   //包裹文件指针
    std::vector< PackageItem >          m_PackageItems; //包裹文件信息,我们用vector来保存
};

Package.cpp

#include "StdAfx.h"
#include "Package.h"

CPackage::CPackage(void)
{
    m_fpPackage = NULL;
}

CPackage::~CPackage(void)
{
    if( m_fpPackage )
    {
        fclose( m_fpPackage );
        m_fpPackage = NULL;
    }
}


bool CPackage::CreatePackage(const char*szPackageName )
{
    //最简单的例子,如果已经创建过包裹了,直接返回失败
    if( m_fpPackage != NULL )
    {
        return false;
    }

    //我们先用标准的C方式创建文件
    m_fpPackage = fopen( szPackageName, "wb" );

    //打开文件失败,返回false
    if( m_fpPackage == NULL )
    {
        printf( "打开文件%s失败\n", szPackageName );
        return false;
    }

    return true;
}

bool CPackage::AddFileToPackage( const char*szFileName )
{   
    //演示方便,我们不做任何重复性重名判断

    //打开目标文件
    FILE*fp = fopen( szFileName, "rb" );
    if( !fp )
    {
        printf( "打开文件%s失败\n", szFileName );
        return false;
    }
    //我们先得到下这个文件大小
    fseek( fp, 0, SEEK_END );
    int FileSize = ftell( fp );
    fseek( fp, 0, SEEK_SET );

    //构建包裹数据
    PackageItem Item;
    strncpy( Item.FileName, szFileName, sizeof( Item.FileName ) - 1 );
    Item.FileSize = FileSize;
    Item.OffsetPackage = ftell( m_fpPackage );
    
    //同样为了演示方便,我们不做任何写入判断
    //先把包裹文件信息写入包裹
    fwrite( &Item, 1, sizeof( Item ), m_fpPackage );
    
    //写入文件数据,我们准备一个64K的缓冲区
    char szBuffer[65536];
    while( 1 )
    {
        //读取文件
        int nReadBytes = fread( szBuffer, 1, sizeof( szBuffer ), fp );

        //写入包裹
        fwrite( szBuffer, 1, nReadBytes, m_fpPackage );

        //如果读取到的数据比缓冲区小,那么说明读取结束了
        if( nReadBytes < sizeof( szBuffer ) )
        {
            break;
        }
    }
    //fflush是确保我们的数据写入到磁盘上了
    fflush( m_fpPackage );

    //关闭文件
    fclose( fp );
    return true;
}

解包程序的实现框架

  1. 新建一个CPackageLoader类(这个类负责解出Package1打包的文件)
  2. 在CPackageLaoder类中添加几个接口
  3. 实现打开包裹文件的OpenPackage函数
  4. 实现得到包裹里面有多少个PackageItemq结构的GetPackageItemCount函数
  5. 实现得到打包文件的信息的GetPackageItem函数
  6. 实现导出包裹文件并保存到szTargetName的ExportPackageItem函数
  7. 测试Package2解包程序

PackageLoader.h

#pragma once

#include <vector>

//先从最简单最简单的开始,以ASCII编码为准
struct PackageItem
{
    char            FileName[256];      //假设文件名定长,不超过256字符
    int             FileSize;           //假设文件不超过2G
    unsigned int    OffsetPackage;      //在包裹的偏移,同样最简单的演示我们假设包裹文件不大于4G
};


class CPackageLoader
{
public:
    CPackageLoader(void);
public:
    ~CPackageLoader(void);

    //打开包裹szPackageName
    bool OpenPackage( const char*szPackageName );
    //得到包裹里面有多少个PackageItem(打包文件)
    int GetPackageItemCount() const;
    //得到打包文件的信息
    const PackageItem* GetPackageItem( int Index );
    //导出包裹文件并保存到szTargetName
    bool ExportPackageItem( const PackageItem*pItem, const char*szTargetName );
private:
    FILE                            *m_fpPackage;
    std::vector< PackageItem >      m_PackageItems;
};

PackageLoader.cpp

#include "StdAfx.h"
#include "PackageLoader.h"
#include <assert.h>

CPackageLoader::CPackageLoader(void)
{
    m_fpPackage = NULL;
}

CPackageLoader::~CPackageLoader(void)
{
    if( m_fpPackage )
    {
        fclose( m_fpPackage );
        m_fpPackage = NULL;
    }
}

bool CPackageLoader::OpenPackage(const char*szPackageName )
{
    //为了演示,我们仅仅提供OpenPackage并不提供ClosePackage功能
    if( m_fpPackage != NULL )
    {
        return false;
    }
    m_fpPackage = fopen( szPackageName, "rb" );
    if( m_fpPackage == NULL )
    {
        printf( "打开%s失败\n", szPackageName   );
        return false;
    }
    //我们先读取所有的PackageItem信息
    while( 1 )
    {
        //简单的格式,没有太多检查,复杂的我们稍后说
        //读取PackageItem结构
        PackageItem Item;
        if( sizeof( Item ) != fread( &Item, 1, sizeof( Item ), m_fpPackage ) )
        {
            break;
        }
        m_PackageItems.push_back( Item );
        //跳过压缩文件的大小,这样下一次循环中,我们就得到下一个Item了
        fseek( m_fpPackage, Item.FileSize, SEEK_CUR );
    }
    return true;
}

int CPackageLoader::GetPackageItemCount() const
{
    return m_PackageItems.size();
}

const PackageItem* CPackageLoader::GetPackageItem(int Index )
{
    if( Index < 0 || Index >= m_PackageItems.size() )
    {
        return NULL;
    }
    return &m_PackageItems[Index];
}

bool CPackageLoader::ExportPackageItem( const PackageItem*pItem, const char*szTargetName )
{
    //为了演示,我们这里去掉了m_fpPackage合法性判断, pItem合法性判断和szTargetName的判断
    FILE*fp = fopen( szTargetName, "wb" );
    if( !fp )
    {
        printf( "打开%s失败\n", szTargetName );
        return false;
    }
    //移动文件指针到指定位置,由于我们的OffsetPackage数据包含了PackageItem信息
    //所以打包文件的真实偏移还需要加上sizeof( PackageItem )
    fseek( m_fpPackage, pItem->OffsetPackage + sizeof( PackageItem ), SEEK_SET );
    //写入文件数据,我们准备一个64K的缓冲区
    char szBuffer[65536];
    //我们需要读取的文件大小
    int LeftSize = pItem->FileSize;
    while( 1 )
    {
        //实际要读取的大小
        int ReadSize = LeftSize;
        //如果大于缓冲区,我们就只读取缓冲区大小的内容,剩余的下次读取
        if( ReadSize > sizeof( szBuffer ) )
        {
            ReadSize = sizeof( szBuffer );
        }
        //读取文件
        int nReadBytes = fread( szBuffer, 1, ReadSize, m_fpPackage );
        //ReadSize必须要等于nReadBytes,演示代码我们不做过多判断
        assert( ReadSize == nReadBytes );
        //写入包裹
        fwrite( szBuffer, 1, nReadBytes, fp );
        LeftSize -= nReadBytes;
        //如果剩余大小为0,就读取完成了
        if( LeftSize == 0 )
        {
            break;
        }
    }
    fclose( fp );
    return true;
}

文件打包学习1

原文:https://www.cnblogs.com/s3320/p/11923268.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!