ZIP 文件读取

    Avatar 引擎可以设置 zip 压缩文件作为引擎运行的资源目录,当指定资源目录为 zip 压缩包时,读取指定的文件也就自动转换为压缩包文件读取。而写文件则不以 zip 压缩包为目标写入,文件管理器在写文件时默认以 zip 文件所在目录作为当前目录进行写文件操作,这样当设置当前目录为 zip 文件时,读取和写入的位置是不一样的。

    先来看看文件管理器部分相关方法

/**
* 设置资源目录
* @param directory 当前资源目录,可以设定为 ZIP 文件路径
* @note 当设定为 ZIP 文件时,GetDataDirectory 返回 ZIP 文件所在目录,另外可以设置解压密码(例如 C:\a.zip?password)
*/
void CFileManager::SetDataDirectory(const string& directory) {
	m_strCurrentDirectory = directory;
	// 销毁 ZIP 读取接口
	if (m_pZipReader) {
		delete m_pZipReader;
		m_pZipReader = 0;
	}
	// directory 为 ZIP 文件
	if (directory.find(".zip") != directory.npos) {
		string filepath = directory;
		string password = "";
		size_t passIndex = directory.find_last_of('?');
		if (passIndex != directory.npos) {
			password = directory.substr(passIndex + 1);
			filepath = directory.substr(0, passIndex);
		}
		m_pZipReader = new CZipReader(filepath, password);
		m_strCurrentDirectory = GetDirectory(filepath);
		if (m_strCurrentDirectory.length() > 0) {
			m_strCurrentDirectory += "/";
		}
	}
	// directory 为普通路径
	if (!m_pZipReader && directory.length() > 0) {
		char lastLetter = directory.at(directory.length() - 1);
		if (lastLetter != '/' && lastLetter != '\\') {
			m_strCurrentDirectory += "/";
		}
	}
}

文件读取

/**
* 读取文件
* @param filename 读取的文件名
* @param file 文件对象指针
* @return 读取成功返回 true
*/
bool CFileManager::ReadFile(const string& filename, CFile* file) {
	unsigned int size = 0;
	unsigned char* data = 0;

	// 清除文件原内容
	if (file->contents) {
		delete[] file->contents;
		file->contents = 0;
		file->size = 0;
	}

	// 如果设定当前目录为压缩文件,则从压缩包中读取
	if (m_pZipReader) {
		if (!m_pZipReader->Open(filename)) return false;
		size = m_pZipReader->Size();
		data = new unsigned char[size];
		m_pZipReader->Read(data, size);
		m_pZipReader->Close();
	} else {
		// 计算完整路径
		string fullpath = filename;
		if (!IsFullPath(filename)) {
			fullpath = m_strCurrentDirectory + filename;
		}
		// 读取文件内容
		ifstream fin(fullpath.c_str(), ios::in | ios::ate | ios::binary);
		if (!fin.is_open()) return false;
		size = (unsigned int)fin.tellg();
		data = new unsigned char[size];
		fin.seekg(0, ios::beg);
		fin.read((char*)data, size);
		fin.close();
	}

	// 根据不同的文件类型进行解析
	bool ret = false;
	switch (file->type) {
	case BIN: ret = ParseBinFile(file, data, size); break;
	case TXT: ret = ParseTxtFile(file, data, size); break;
	case BMP: ret = ParseBmpFile(file, data, size); break;
	case TGA: ret = ParseTgaFile(file, data, size); break;
	case PNG: ret = ParsePngFile(file, data, size); break;
	case JPG: ret = ParseJpgFile(file, data, size); break;
	case WAV: ret = ParseWavFile(file, data, size); break;
	case MP3: ret = ParseMp3File(file, data, size); break;
	}
	delete[] data;
	return ret;
}
文件写入

/**
* 写入文件
* @param filename 写入的文件名
* @param file 文件对象指针
* @return 写入成功返回 true
*/
bool CFileManager::WriteFile(const string& filename, CFile* file) {
	unsigned int size = 0;
	unsigned char* data = 0;

	// 检查文件内容是否为空
	if (!file->contents) {
		return false;
	}

	// 根据不同的文件类型进行序列化
	bool ret = false;
	switch (file->type) {
	case BIN: ret = SerializeBinFile(file, &data, &size); break;
	case TXT: ret = SerializeTxtFile(file, &data, &size); break;
	case BMP: ret = SerializeBmpFile(file, &data, &size); break;
	case TGA: ret = SerializeTgaFile(file, &data, &size); break;
	case PNG: ret = SerializePngFile(file, &data, &size); break;
	case JPG: ret = SerializeJpgFile(file, &data, &size); break;
	case WAV: ret = SerializeWavFile(file, &data, &size); break;
	case MP3: ret = SerializeMp3File(file, &data, &size); break;
	}
	if (!ret) return false;
	// 计算完整路径
	string fullpath = filename;
	if (!IsFullPath(filename)) {
		fullpath = m_strCurrentDirectory + filename;
	}
	// 写入文件内容
	ofstream fout(fullpath.c_str(), ios::out | ios::binary | ios::trunc);
	if (fout.is_open()) {
		fout.write((char*)data, size);
		fout.close();
		delete[] data;
		return true;
	}
	delete[] data;
	return false;
}
    以上代码解释了 Avatar 引擎的文件管理器对文件的读取和写入的操作方式。

    好了,现在我们回过来看看 zip 文件读取类(CZipReader)的定义,注意其中用到了 zlib 开源库。

//================================================
// Copyright (c) 2016 周仁锋. All rights reserved.
// ye_luo@qq.com
//================================================
#ifndef _CZIPREADER_H_
#define _CZIPREADER_H_
#include "thirdparty/zlib/zlib.h"
#include "thirdparty/zlib/unzip.h"
#include <string>
using namespace std;

/**
* ZIP 文件读取类
*/
class CZipReader {
public:
	CZipReader(const string& path, const string& password);
	~CZipReader();

public:
	//! 打开压缩包中的指定文件
	bool Open(const string& file);
	//! 关闭上次打开的文件
	void Close();
	//! 获取当前打开的文件大小
	unsigned int Size();
	//! 读取当前打开的文件
	unsigned int Read(unsigned char* buff, unsigned int size);

private:
	//! 解压句柄
	unzFile m_pZipFile;
	//! 打开的文件信息
	unz_file_info64 m_sFileInfo;
	//! 压缩包解压密码
	string m_strPassword;
};

#endif
CZipReader实现代码

//================================================
// Copyright (c) 2016 周仁锋. All rights reserved.
// ye_luo@qq.com
//================================================
#include "CZipReader.h"
#include "CLog.h"
#include "Configure.h"
#include "thirdparty/zlib/unzip.c"
#include "thirdparty/zlib/ioapi.c"
#include <string.h>

#ifdef AVATAR_WINDOWS
#pragma comment(lib, "thirdparty/zlib/zlib.lib")
#endif

/**
* 构造函数,指定压缩包路径和解压密码
*/
CZipReader::CZipReader(const string& path, const string& password) {
	m_strPassword = password;
	m_pZipFile = unzOpen64(path.c_str());
	if (!m_pZipFile) {
		CLog::Error("Open zip file '%s' error", path.c_str());
	}
}

/**
* 析构函数
*/
CZipReader::~CZipReader() {
	if (m_pZipFile) {
		unzClose(m_pZipFile);
	}
}

/**
* 打开压缩包中的指定文件
*/
bool CZipReader::Open(const string& file) {
	memset(&m_sFileInfo, 0, sizeof(unz_file_info64));
	if (!m_pZipFile) return false;
	if (unzLocateFile(m_pZipFile, file.c_str(), 0) != UNZ_OK) return false;
	if (unzGetCurrentFileInfo64(m_pZipFile, &m_sFileInfo, 0, 0, 0, 0, 0, 0) == UNZ_OK) {
		const char* password = 0;
		if (m_strPassword.length()) {
			password = m_strPassword.c_str();
		}
		if (unzOpenCurrentFilePassword(m_pZipFile, password) == UNZ_OK) {
			return true;
		}
	}
	return false;
}

/**
* 关闭上次打开的文件
*/
void CZipReader::Close() {
	memset(&m_sFileInfo, 0, sizeof(unz_file_info64));
	if (m_pZipFile) {
		unzCloseCurrentFile(m_pZipFile);
	}
}

/**
* 获取当前打开的文件大小
*/
unsigned int CZipReader::Size() {
	if (m_pZipFile) {
		return (unsigned int)m_sFileInfo.uncompressed_size;
	}
	return 0;
}

/**
* 读取当前打开的文件
*/
unsigned int CZipReader::Read(unsigned char* buff, unsigned int size) {
	if (m_pZipFile) {
		return unzReadCurrentFile(m_pZipFile, buff, size);
	}
	return 0;
}
    好了,到这里基本上完结了,但我在使用时发现了一个问题,在读取加密的文件时总是失败,通过查看 zlib 库的 unzip.c 源文件发现定义了 NOUNCRYPT 这个宏,注释掉就没问题了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值