二进制 bin文件 合成工具

二进制 bin文件 合成工具

文章目录

  • 二进制 bin文件 合成工具
    • 1、功能介绍
    • 2、`EXE`工具下载与使用
      • 2.1 百度网盘下载自取
      • 2.2 `EXE`工具如何使用
        • 2.2.1 bin文件命名规范
        • 2.2.2 通过`cmd`命令,生成 `prj.txt`
    • 3、流程介绍
    • 4、程序介绍
    • 5、将c语言文件打包成`exe`可执行程序

1、功能介绍

  • bin文件合成工具,是一个将指定bin文件进行合并的的工具;在自定义flash分区,进行各种差分文件的逻辑组合中起到很大的作用;
  • 差分bin文件合成为普通文件,生成SPL-2MB_0x0.bin文件;
  • 学习此篇文章,你将学会
    1. 通过 cmd 命令行,生成含有 该文件夹中 以.bin为后缀文件名 的txt文件;
    2. bin文件进行合成的程序逻辑
    3. 将c语言文件打包成exe可执行程序

2、EXE工具下载与使用

2.1 百度网盘下载自取

  • 链接:https://pan.baidu.com/s/14udJ_4X8Gf0b82o2KeHA6w?pwd=2222
    提取码:2222

2.2 EXE工具如何使用

  • 我们需要
    • 正确的bin文件命名规范;
    • 含有该目录下,所有bin文件全称的 txt文件,我们把它命名prj.txt;
    • bin文件合成工具.exe (通过网盘下载)
2.2.1 bin文件命名规范
  • 命名:【 名称_十六进制地址.bin】
  • tips: 程序中 以”“来区分 文件名称 和 十六进制地址,所以名称与地址之间,要以“” 进行分割;(名称中不可包含 “_”(下划线) ,可以使用“-”)
2.2.2 通过cmd命令,生成 prj.txt
dir *.bin /b > prj.txt
  • 创建一个文本文件prj.txt,列出当前目录下所有的.bin文件:

  • 这条命令的组成部分解释如下:

命令 说明
dir 列出文件和目录的命令
*.bin 指定了 dir 命令要查找的文件模式,即所有以 .bin 结尾的文件
/b 是命令的一个选项,它告诉 dir 命令使用简洁格式(bare format),只输出文件名,不包括文件大小、日期等其他信息。
>> 是重定向操作符,它将命令的输出追加到指定的文件末尾,而不是覆盖文件内容
prj.txt 是接收输出的文件名。

  • 命令行使用说明

1、在当前目录下运行·cmd,输入命令:dir *.bin /b > prj.txt 自动 创建一个文本文件 prj.txt,列出当前目录下所有的 .bin文件:

2、包含文件名的文件命名位 prj.txt,里面每一行都包含了对应的一个.bin文

4、eg:01boot0_0x000000.bin

5、.txt文件和.bin文件与.exe文件在同一目录下运行


如果您想要将文件名追加到现有 prj.txt 文件中,而不是覆盖它,可以使用 >> 代替 >

这将把列出的文件名添加到 prj.txt 文件的末尾,而不是创建一个新文件或覆盖现有文件。

dir *.bin /b >> prj.txt

3、流程介绍

  • 注意命名规范

二进制 bin文件 合成工具_第1张图片

  • 通过cmd生成prj.txt 文件
    二进制 bin文件 合成工具_第2张图片

  • 使用EXE合成工具

二进制 bin文件 合成工具_第3张图片



看到这里,大多数同学已经不用再往下看了,上述内容已经足够实现你的既定目标了,如果你只是想实现bin文件合并的目标。

如果开发时间充裕,对实现逻辑感兴趣,可以接着阅读;

4、程序介绍

#include     // 包含标准输入输出库
#include    // 包含标准库函数
#include    // 包含字符串处理函数
#include     // 包含错误号定义

#define BUFFER_SIZE 1024            // 定义缓冲区大小为1024字节
#define PADDING_BYTE 0xFF           // 定义填充字节为0xFF
#define ALIGNMENT_SIZE 4096         // 定义对齐大小为4096字节

// 定义地址数组
#define BUFFER_SIZE 1024
#define MAX_ADDRESSES 100 // 假设地址的数量不会超过100个
#define _CRT_SECURE_NO_WARNINGS // 禁用安全警告

// 定义宏以禁用安全警告
#define _CRT_SECURE_NO_WARNINGS

// 函数声明
int extract_addresses(const char *filename, uintptr_t *addresses, size_t *count);
/*

*/
int main() {
	FILE *file, *outfile, *temp; // 文件指针数组,分别指向文件列表文件、输出文件和临时二进制文件
	char filename[] = "prj.txt"; // 定义文件名列表文件的名称
	char buffer[BUFFER_SIZE];    // 定义缓冲区,用于存储文件名和读取文件内容
	char bin_filename[BUFFER_SIZE]; // 定义缓冲区,用于存储二进制文件的完整名称
	char address_str[25];        // 定义缓冲区,用于存储24位十六进制地址字符串(加上"0x"前缀)
	char outfilename[] = "SPL-2MB_0x0.bin"; // 定义输出二进制文件名
	long long int address;       // 定义长整型变量,用于存储地址
	char *token;                 // 定义字符指针,用于字符串分割
	char *address_ptr;           // 定义字符指针,用于定位地址字符串
	char *bin_file_ptr;          // 定义字符指针,用于定位bin文件名

	char next_file_index = 1;//下一个文件地址 索引
	char file_len = 0;


	//找地址
	printf("===================\n");
	uintptr_t addresses[MAX_ADDRESSES]; // 存储地址值的数组
	size_t address_count = 0;

	// 调用函数提取地址
	if (extract_addresses("prj.txt", addresses, &address_count) != 0) {
		perror("Error extracting addresses");
		return EXIT_FAILURE;
	}

	// 打印提取出的地址
	for (size_t i = 0; i < address_count; ++i) {
		printf("Address %zu: %p\n", i + 1, (void*)addresses[i]);
		//printf("Address %zu: %p\n", i + 1, addresses[i]);
		file_len++;
	}
	printf("file num = %d\n", file_len);
	printf("====================\n");
	
	

								 // 尝试以只读模式打开文件列表文件
	if (fopen_s(&file, filename, "r") != 0) {
		perror("Error opening file"); // 如果打开失败,输出错误信息
		return EXIT_FAILURE;          // 返回失败状态
	}

	// 创建输出二进制文件,用于写入合并后的内容
	if (fopen_s(&outfile, outfilename, "wb+") != 0) {
		fclose(file); // 如果创建失败,关闭已打开的文件列表文件
		perror("Error creating output binary file"); // 输出错误信息
		return EXIT_FAILURE; // 返回失败状态
	}

	// 使用fgets函数逐行读取文件列表文件   //读prj.txt   prj.txt ==> file ==>   一行行读
	while (fgets(buffer, sizeof(buffer), file) != NULL)
	{
		// 去除可能的换行符
		buffer[strcspn(buffer, "\n")] = 0;

		// 查找地址字符串的开始位置,即第一个"_"字符后面的内容
		token = strchr(buffer, '_');
		if (token == NULL) {
			fprintf(stderr, "Invalid format in file list: missing '_'\n"); // 如果格式错误,输出错误信息
			continue; // 继续处理下一行
		}

		// 复制文件名到bin_filename,不包括地址和.bin
		strncpy_s(bin_filename, sizeof(bin_filename), buffer, token - buffer);
		bin_filename[token - buffer] = '\0'; // 确保字符串以空字符结尾

											 // 查找地址字符串,地址字符串以"_"开始,到".bin"结束
		address_ptr = token + 1;
		if (sscanf_s(address_ptr, "0x%24s", address_str, (unsigned)_countof(address_str)) != 1) {
			fprintf(stderr, "Invalid address format in file list.\n"); // 如果地址格式错误,输出错误信息
			continue; // 继续处理下一行
		}

		// 将十六进制地址转换为长长整型
		address = strtoll(address_str, NULL, 16);

		// 查找bin文件名的开始位置,即地址字符串结束后的第一个"."字符
		bin_file_ptr = strchr(address_ptr, '.');
		if (bin_file_ptr == NULL) {
			fprintf(stderr, "Invalid format in file list: missing '.bin'\n"); // 如果格式错误,输出错误信息
			continue; // 继续处理下一行
		}

		// 复制bin文件名,包括.bin扩展名
		strncpy_s(bin_filename, sizeof(bin_filename), buffer, bin_file_ptr - buffer + 4); // +4 为了包括".bin"
		bin_filename[bin_file_ptr - buffer + 4] = '\0'; // 确保字符串以空字符结尾

														// 打印出每个文件的初始地址
		printf("\nWriting %s to address: 0x%llx\n", bin_filename, address);

		// 移动到指定的写入地址
		if (fseek(outfile, address, SEEK_SET) != 0) {
			perror("Error seeking to the specified address"); // 如果定位失败,输出错误信息
			fclose(file);
			fclose(outfile);
			return EXIT_FAILURE; // 返回失败状态
		}

		// 打开下一个 bin 文件
		if (fopen_s(&temp, bin_filename, "rb") != 0) {
			perror("Error opening binary file listed in prj.txt"); // 如果打开失败,输出错误信息
			continue; // 如果文件打开失败,继续下一个文件
		}

		// 将当前 bin 文件的内容复制到输出文件的指定地址
		size_t bytesRead;
		while ((bytesRead = fread(buffer, 1, sizeof(buffer), temp)) > 0) {
			fwrite(buffer, 1, bytesRead, outfile); // 写入到指定地址
		}

		fclose(temp); // 关闭当前 bin 文件

					  // 移动到下一个文件的起始位置


		
					  // 计算当前位置到下一个文件起始位置的距离addresses[i]
		if(file_len > 1)
		{ 
			//printf("file_len =%d\n", file_len);
			long long int current_position = _ftelli64(outfile);
			long long int offset_to_next_file = addresses[next_file_index] - current_position;
		
			printf("=====current_position = %p =====\n", current_position);
			printf("=====下一个文件的起始位置 address = %p =====\n", addresses[next_file_index]);
			printf("=====距离下个文件的距离offset_to_next_file = %p =====\n", offset_to_next_file);
		
			next_file_index++;
			// 如果存在偏移,用0xFF填充
			if (offset_to_next_file > 0)
			{
				printf("Filling %lld bytes with 0xFF until next file address.\n", offset_to_next_file);
				while (offset_to_next_file > 0)
				{
					size_t bytes_to_write = (size_t)(offset_to_next_file > sizeof(buffer) ? sizeof(buffer) : offset_to_next_file);
					memset(buffer, PADDING_BYTE, bytes_to_write); // 用0xFF填充缓冲区
					fwrite(buffer, 1, bytes_to_write, outfile); // 写入填充字节
					offset_to_next_file -= bytes_to_write; // 更新剩余需要填充的字节数
				}
			}
			
			file_len--;
		}
		
		
	}

	/* 补齐 */
	// 关闭所有打开的文件
	fclose(file);
	fclose(outfile);

	// 重新打开输出文件以进行填充操作
	if (fopen_s(&outfile, outfilename, "rb+") != 0) {
		perror("Error reopening output binary file for padding"); // 如果重新打开失败,输出错误信息
		return EXIT_FAILURE; // 返回失败状态
	}

	// 获取输出文件的当前大小
	long long int current_size = _ftelli64(outfile);

	// 计算需要补齐的字节数,以确保文件大小是ALIGNMENT_SIZE字节的整数倍
	long long int padding_bytes = (current_size % ALIGNMENT_SIZE) ? (ALIGNMENT_SIZE - (current_size % ALIGNMENT_SIZE)) : 0;

	// 如果需要补齐,填充剩余的字节为0xFF
	if (padding_bytes > 0) {
		printf("Adding %lld bytes (0xFF) to reach a size that is a multiple of %lld bytes.\n", padding_bytes, ALIGNMENT_SIZE);
		char padding_buffer[ALIGNMENT_SIZE]; // 定义填充缓冲区
		memset(padding_buffer, PADDING_BYTE, sizeof(padding_buffer)); // 填充缓冲区为0xFF

		while (padding_bytes > 0) {
			size_t bytes_to_write = (size_t)(padding_bytes < sizeof(padding_buffer) ? padding_bytes : sizeof(padding_buffer));
			fwrite(padding_buffer, 1, bytes_to_write, outfile); // 写入填充字节
			padding_bytes -= bytes_to_write; // 更新剩余需要填充的字节数
		}
	}

	// 关闭输出二进制文件
	fclose(outfile);

	system("pause"); // 暂停,以便查看程序输出
	return EXIT_SUCCESS; // 返回成功状态
}


// 从文件中提取地址的函数实现
int extract_addresses(const char *filename, uintptr_t *addresses, size_t *count) {
	FILE *file;
	char buffer[BUFFER_SIZE];
	char *token;
	uintptr_t address = 0; // 确保address变量初始化为0

						   // 打开文件
	if (fopen_s(&file, filename, "r") != 0) {
		perror("Error opening file");
		return -1; // 返回-1表示失败
	}

	*count = 0; // 初始化地址计数为0

				// 读取文件直到末尾
	while (fgets(buffer, sizeof(buffer), file) != NULL && *count < MAX_ADDRESSES) {
		// 去除可能的换行符
		buffer[strcspn(buffer, "\n")] = 0;

		// 查找地址字符串的开始位置,即第一个"_"字符后面的内容
		token = strchr(buffer, '_');
		if (token == NULL) {
			fprintf(stderr, "Invalid format in file list: missing '_'\n");
			continue;
		}

		// 跳过下划线
		token += 1;

		// 查找文件扩展名 ".bin" 之前的部分
		char *end_ptr = strstr(token, ".bin");
		if (end_ptr != NULL) {
			*end_ptr = '\0'; // 终止字符串以获取纯净的地址
			address = strtoull(token, NULL, 16); // 转换为无符号长长整型
			if (errno == EINVAL || errno == ERANGE) {
				perror("Error converting address");
				fclose(file);
				return -1; // 返回-1表示失败
			}
		}
		else {
			fprintf(stderr, "Invalid format in file list: missing '.bin'\n");
			continue;
		}

		// 存储地址值
		addresses[(*count)++] = address;
	}

	fclose(file);
	return 0; // 成功返回0
}
  • 这套程序并不适用于所有项目,每个项目都有自己的一套bin文件规则,大家可以稍作修改使用;

5、将c语言文件打包成exe可执行程序

  • 我用的编译器是Visual Studio 2015

    1、将 Debug ==> Release
    二进制 bin文件 合成工具_第4张图片

2、==> 编译
二进制 bin文件 合成工具_第5张图片

3、在该工程目录下,找到

二进制 bin文件 合成工具_第6张图片



欢迎大家一起交流讨论

你可能感兴趣的:(数据库,服务器,c,工具,开发,软件工程师)