文件加密
- 思路采用C语言命令行方式提取文件字节读入和写入,将文件指针获取文件内容移至末尾,采用成员函数tellg()获取的当前文件位置,然后循环获取单个字符一个个进行加密,最后写入目标文件。加密文件过大可能会超streamoff范围。
- 具体函数成员看官方帮助文档:https://learn.microsoft.com/zh-cn/cpp/standard-library/input-stream-member-functions?view=msvc-170
#include <iostream>
#include <fstream>
int main(int argc,char* argv[])
{
std::fstream SourceFile;
SourceFile.open(argv[1], std::ios::in | std::ios::binary);//源文件
std::fstream DistFile;
DistFile.open("xiaogua.png", std::ios::out | std::ios::binary);//目标加密文件
char temp;//定义一个临时的字符变量
SourceFile.seekg(0, std::ios::end);//设置文件内容指针到文件末尾
std::streamoff fileSize = SourceFile.tellg();//获取文件内容指针到文件头的字节数
SourceFile.seekg(0, std::ios::beg);//设置文件内容指针返回到文件头
for (std::streamoff i = 0; i < fileSize; i++)
{
temp = SourceFile.get();
temp = (temp + 10) ^ 20;//二次加密
DistFile.put(temp);//写入到目标文件
}
SourceFile.close();
DistFile.close();
return 0;
}
- 操作演示:
-
我们此时运行程序是会报错的,因为采用的命令行的方式提取文件,运行是没有文件的一定会报错,我们需要将图片拖入生成加密的exe程序中
-
然后会生成一个xiaogua.png加密的格式文件
-
此时这个文件就加密了,我们可以用winhex看看文件是否被加密
-
此时就可以看出这个png被二次运算了,程序里面是先加10后异或20,那么我们需要解密就是先异或20后减10,注意20在winhex里面是采用16进制,也就是在winhex里面要异或14
-
此时xiaogua.png文件就解密成功了
-
拓展文件加密器功能
- 我们可以使用Windows的库来将生成的文件删除,然后只剩下加密的源文件,这次采用一次异或加密,就可以做到加密解密同一个程序完成,至于为什么参考异或运算的法则,使用windows库时记得把项目属性改成多字节字符集
- 代码如下:
#include <iostream>
#include <fstream>
#include <windows.h>
int main(int argc,char* argv[])
{
std::fstream SourceFile;
SourceFile.open(argv[1], std::ios::in | std::ios::binary);//源文件
std::fstream DistFile;
DistFile.open("xiaogua.png", std::ios::out | std::ios::binary);//目标加密文件
if (!SourceFile || !DistFile)
{
std::cout << "打开文件失败" << std::endl;
}
char temp;//定义一个临时的字符变量
SourceFile.seekg(0, std::ios::end);//设置文件内容指针到文件末尾
std::streamoff fileSize = SourceFile.tellg();//获取文件内容指针到文件头的字节数
SourceFile.seekg(0, std::ios::beg);//设置文件内容指针返回到文件头
for (std::streamoff i = 0; i < fileSize; i++)
{
temp = SourceFile.get();
temp ^= 20;//加密
DistFile.put(temp);//写入到目标文件
}
SourceFile.close();
DistFile.close();
DeleteFile(argv[1]);//删除还没有加密的原文件
MoveFile("xiaogua.png", argv[1]);//将原名改为加密后的文件名
return 0;
}
- 结果
文件打包与解包
- 首先把项目属性改成多字节字符集
- 打包思路:简单模拟一下文件打包,文件打包存放信息,有文件信息与文件内容,所以我们可以建立一个结构体用来存储文件的大小和文件名,然后获取到文件数量后分配一段文件多少的内存,将每个文件名存入到结构体中,然后将每个文件的大小存入结构体中,最后将每个文件大小个数和内容信息写入目标打包文件中
#include <iostream>
#include <fstream>
#include <windows.h>
struct fileInfo
{
//建议字符串内存给大点
char fileName[1024];//文件名
std::streamoff fileSize;//文件大小
};
int main(int argc, char* argv[])
{
//获取文件数量
int numFile = argc - 1;
//动态内存分配一段文件大小
fileInfo* FileArr = new fileInfo[numFile];
memset(FileArr, 0, numFile * sizeof(fileInfo));
//保存每个文件名
for (int i = 0; i < numFile; i++)
{
strcpy(FileArr[i].fileName, argv[i + 1]);//保存文件名
}
std::fstream SourceFile;
std::fstream distFile;
distFile.open("xiaogua.xiaogua", std::ios::out | std::ios::binary);
//保存每个文件大小
for (int i = 0; i < numFile; i++)
{
SourceFile.open(FileArr[i].fileName, std::ios::in | std::ios::binary);
SourceFile.seekg(0, std::ios::end);
FileArr[i].fileSize = SourceFile.tellg();
SourceFile.seekg(0, std::ios::beg);
SourceFile.close();
}
//文件个数信息写入打包文件中
distFile.write((char*)&numFile, sizeof(int));
//文件大小信息写入打包文件中
distFile.write((char*)FileArr, numFile * sizeof(fileInfo));
//循环写入打包文件
for (int i = 0; i < numFile; i++)
{
SourceFile.open(FileArr[i].fileName, std::ios::in | std::ios::binary);
for (std::streamoff j = 0; j < FileArr[i].fileSize; j++)
{
distFile.put(SourceFile.get());
}
SourceFile.close();
}
distFile.close();
return 0;
}
- 解包思路:首先得获取文件的数量,从命令行中获取到文件,读出文件数量,然后分配这个数量的内存,直接一次性读出文件信息,循环创建写入文件即可
#include <iostream>
#include <fstream>
#include <windows.h>
struct fileInfo
{
//建议字符串内存给大点
char fileName[1024];//文件名
std::streamoff fileSize;//文件大小
};
int main(int argc, char* argv[])
{
int numFile;//文件数量
std::fstream SourceFile, distFile;
//读取文件大小
SourceFile.open(argv[1], std::ios::in | std::ios::binary);
SourceFile.read((char*)&numFile, sizeof(int));
//申请一段文件内存
fileInfo* fileArr = new fileInfo[numFile];
memset(fileArr, 0, numFile * sizeof(fileInfo));
//从文件中读出要解包的文件信息
/*for (int i = 0; i < numFile; i++)//等同下面一句,因为是数组可以一次性读出
{
SourceFile.read((char*)&fileArr[i], sizeof(fileInfo));
}*/
SourceFile.read((char*)fileArr, numFile * sizeof(fileInfo));//一次性读出
//循环创建写入文件
for (int i = 0; i < numFile; i++)
{
distFile.open(fileArr[i].fileName, std::ios::out | std::ios::binary);
for (std::streamoff j = 0; j < fileArr[i].fileSize; j++)
{
distFile.put(SourceFile.get());
}
distFile.close();
}
SourceFile.close();
return 0;
}
- 运行结果