SPL-2MB_0x0.bin
文件;cmd
命令行,生成含有 该文件夹中 以.bin
为后缀文件名 的txt
文件;bin
文件进行合成的程序逻辑exe
可执行程序EXE
工具下载与使用EXE
工具如何使用txt
文件,我们把它命名prj.txt
;bin文件合成工具.exe
(通过网盘下载)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
看到这里,大多数同学已经不用再往下看了,上述内容已经足够实现你的既定目标了,如果你只是想实现bin文件合并的目标。
如果开发时间充裕,对实现逻辑感兴趣,可以接着阅读;
#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
}
exe
可执行程序3、在该工程目录下,找到
欢迎大家一起交流讨论