Linux内核编程 文件的拆分、拼合操作

目录 

一:前言

二:需求

三:实现


一:前言

网络中上传下载文件(网络中文件传输功能)

需要使用到 拆分拼合 文件操作

二:需求

文件的拆分和文件的拼合操作

要求如下

1.程序运行给定一个文件路径

2.写一个拆分文件函数,创建一个文件夹,将给定路径拆分成碎片文件保存在这个文件夹中

3.要求拆分出来的N个碎片文件总大小和原文件相同

4.写一个拼合文件函数,将前面拆分好的碎片文件拼合成一个完整的文件

例如:

一个1.jpg文件,拆分等 到一个文件夹内部N个x.temp碎片文件,

最终可以将这些碎片文件拼合成一个完整的final.jpg,并且这个图片文件依然可以双击查看

拆分:read读一个文件,write写多个文件

拼合:read读多个文件,write写一个文件 

主要问题:

1.存储字节设计

    //1000个字节 1KB 拆分出来的不是1024而是1000,按照硬盘产商规格来写
	//产商制作硬盘是按照1000制作 1024 = 1.03KB
	char buf[1000] = { 0 };

2.拆分拼合文件名的排序问题

a.链表排序(指针指向),会出现如下排序 是乱序的

b. 需要排序成 1 2 3 4 5 顺序  【有顺序的才能成为排序】

本来打算使用自带的排序,但是会出现问题 (按照字符串ASCII排序)

由于

	//保存所有路径 
    //list内存空间利用率高,适合频繁插删
	list<string> paths;//list容器用来保存多个路径(读多个文件,所有文件有路径,需要保存)
	list<string>::iterator iter;//遍历 迭代器

是string字符串,字符串排序是ASCII码排序,会出现如下排序

因此不能使用自带的排序

VS2019中多行注释快捷键:

ctrl + shift + /     注释多行

        //paths.sort();

		//快速排序 sort(起始位置,结束位置,排序算法函数指针)、

		/*
		* bool true false
		* return 0 交换位置
		* return 1 保持不变
		*
		 bool cmp(string &a,string &b)
		 {
			return a>b;
		 }

		 sort(paths.begin(),paths.end(),cmp)

		 大口朝前大在前(从大到小),小口朝前小在前(从小到大)

		*/

		/*cout << "--------------排序后-----------------------------------" << endl;

		for (iter = paths.begin(); iter != paths.end(); iter++)
		{
			cout << *iter << endl;
		}*/

c. 目标是排序成1 2 3 4 5顺序

    最后使用如下排序解决问题

//重构 list<string> 路径列表的排序sort
		paths.sort(
			[](const string& a, const string& b) 
			{
				//字符串排序->整型排序  find得到下标先转char类型 再atoi转整型
			return atoi(a.substr(10, a.find(".")).c_str()) < atoi(b.substr(10, b.find(".")).c_str()); 
			}
		);

三:实现

文件的拆分+文件的拼合  [代码实现] 

目标,将3.jpg图片文件,拆分文件,

拼合文件至 123文件夹下

具体实现如下

#include <iostream>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <stdio.h>
#include <fcntl.h>
#include <list>
#include <algorithm>

using namespace std;

//拆分文件:读一个文件,写(创建)多个文件
int SplitFile(char filepath[])
{
	int readfd = 0;
	int writefd = 0;
	//返回值
	int resbuf = 0;
	//1000个字节 1KB 拆分出来的不是1024而是1000,按照硬盘产商规格来写
	//产商制作硬盘是按照1000制作 1024 = 1.03KB
	char buf[1000] = { 0 };
	char writePath[30] = { 0 };
	//第一个文件设置为1
	int num = 1;
	umask(0);
	readfd = open(filepath, O_RDONLY, 0777);

	if (readfd < 0)
	{
		perror("open dir error");
	}
	else {
		while ((resbuf = read(readfd, buf, sizeof(buf))) > 0)
		{
			//第一个文件:1.temp
			sprintf(writePath, "/root/123/%d.temp", num);
			cout << "writePath = " << writePath << endl;
			//拼接好路径后再open打开
			writefd = open(writePath, O_CREAT | O_WRONLY, 0777);
			//resbuf读到多少,写多少
			int res = write(writefd, buf, resbuf);
			if (res > 0)
			{
				//文件拆分,先关闭写,文件还未读完
				close(writefd);
				//写一次就一个文件,num++下一个就是 2.temp文件
				num++;
				//读内容的清空
				bzero(buf, sizeof(buf));
				//路径的清空,因为在下一次生成一个新的路径 num++
				bzero(writePath, sizeof(writePath));
			}
		}
		//文件拆分 先关闭写 后关闭读
		close(readfd);
		return num;
	}

	return 0;
}

//拼合文件:读多个文件,写一个文件
int CohereFile(char filepath[])
{
	int readfd = 0;
	int writefd = 0;
	int resbuf = 0;
	//一个buf装一个零碎的temp文件
	char buf[1000] = { 0 };
	//读路径
	char writePath[30] = { 0 };
	//写路径
	char readPath[30] = { 0 };
	//保存所有路径 
    //list内存空间利用率高,适合频繁插删
	list<string> paths;//list容器用来保存多个路径(读多个文件,所有文件有路径,需要保存)
	list<string>::iterator iter;//遍历 迭代器

	umask(0);
	//结构体指针DIR
	DIR* dir = NULL;
	//结构体指针dirent
	struct dirent* pdir = NULL;

	if ((dir = opendir(filepath)) == NULL)
	{
		perror("opendir error");
	}
	else {
		while ((pdir = readdir(dir)) != NULL)
		{
			// /root/123/1.temp     /root/123/2.temp    /root/123/3.temp
			if (strcmp(pdir->d_name, ".") == 0 || strcmp(pdir->d_name, "..") == 0)
			{
				continue;
			}
			bzero(readPath, sizeof(writePath));
			//完整路径拼接
			strcat(readPath, filepath);
			strcat(readPath, "/");
			strcat(readPath, pdir->d_name);
			//各个.temp文件路径 存入链表中
			paths.push_back(readPath);
		}

		cout << "paths.size() = " << paths.size() << endl;

		//测试打印路径
		//for (iter = paths.begin(); iter != paths.end(); iter++)
		//{
		//	cout << *iter << endl;
		//}

		//  例如/root/123/1.temp  /root/123/10.temp 路径  只要获取1 10 

		//重构 list<string> 路径列表的排序sort
		paths.sort(
			[](const string& a, const string& b) 
			{
				//字符串排序->整型排序  find得到下标先转char类型 再atoi转整型
			return atoi(a.substr(10, a.find(".")).c_str()) < atoi(b.substr(10, b.find(".")).c_str()); 
			}
		);

		bzero(writePath, sizeof(writePath));
		strcat(writePath, filepath);
		strcat(writePath, "/");
		strcat(writePath, "CohereFile.jpg");
		writefd = open(writePath, O_CREAT | O_WRONLY, 0777);

		for (iter = paths.begin(); iter != paths.end(); iter++)
		{
			//排序后打印路径
			cout << *iter << endl;
			//迭代器遍历 链表中存放的 路径
			readfd = open((*iter).c_str(), O_RDONLY, 0777);
			cout << "(*iter).c_str() = " << (*iter).c_str() << endl;
			if (readfd < 0)
			{
				perror("open dir error");
			}
			else {
				cout << "sizeof(buf) = " << sizeof(buf) << endl;

				while ((resbuf = read(readfd, buf, sizeof(buf))) != 0)
				{
					write(writefd, buf, resbuf);
				}
				close(readfd);
			}
		}
		close(writefd);

		return 1;
	}

	return 0;
}

int main()
{
	int x = SplitFile("/root/3.jpg");
	if (x > 0)
	{
		cout << "拆分文件完成" << endl;
		cout << "可以开始拼合文件" << endl;
		int n = CohereFile("/root/123");
		if (n > 0)
		{
			cout << "拼合文件完成" << endl;
		}
		else {
			cout << "拼合文件失败" << endl;
		}
	}
	else {
		cout << "拆分文件失败" << endl;
	}

	return 0;
}

查看结果:

打开123文件夹,发现文件成功拆分 、文件成功拼合

同时拼合的文件可以双击查看(拆分 拼合 文件 没有问题)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chenruhan_QAQ_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值