【C】ASCII 的十六进制字符转文件

概述

本项目是我自己使用的

来源于用串口传文件数据到电脑进行分析的时候,需要转换成可以打开的文件

而常用的串口助手大都没有直接保存为二进制文件的功能

也完全可以当作c语言初学者的练习项目(很简单)

需求

用串口传来的文件是如下格式(ASCII字符)

需要将其转化为二进制数据,使其可以打开

如下(上图是记事本打开的文本文件,下图是winhex打开的二进制文件)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GaFPSYFn-1675908462293)(picture/1.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2x969fi3-1675908462298)(picture/2.png)]

另外需要运行效率相对较高(有时候会有Gb级文件解码的需要)

附加:便于使用,目前设计的是拖动要转化的文件到程序上,可以自动将其转化并输出文件(带后缀名)到指定目录

方案

核心程序选用C语言设计,本人对C相对熟悉,C语言的执行效率较高,可编译成exe文件

外围输入输出使用bat文件(批处理),获取拖入的文件名,及更改输出的文件名和位置

程序

C

控制台传参

当我们把主函数(main)定义成特殊形式时,我们可以在控制台(cmd)调用exe时向函数传递参数

如下图所示,则可以传入3个参数 第一个参数是1 第二个参数是2 (参数间用空格分开,为char *型)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UQ0b8OnZ-1675908462298)(picture/3.png)]

我们把主函数定义为如下形式时即可实现这个功能

int main(int argc, char *argv[])
{

}

argc:是参数数量,上例子中为4(包括一开始的exe文件路径)

argv:是参数的内容

上例中 argv[0]是text.exe的全路径名(一般用不到)

argv[1]是"a1"

argv[2]是"a2"

argv[3]是"a3"

在本项目中,我设计传入的参数有3个,

第一个是被解析文件的全路径(绝对路径)(C:\home\1.txt)

第二个是输出文件名(为了区分,在程序中让这个文件名加上了后缀)(如 outputfile)(支持目录前缀 相对目录)

第三个是文件的后缀名(.jpeg)

输出文件名检测

这个部分是为了应对文件名出现重复的情况

例子:假设要输出的文件名是out ,但是输出目录下有了这个文件,则我需要让他输出out1

如果这个也有了则让他输出out2依次类推

设计是大于某个数(1000000)时则认为出错,也就是out1000000

思路:设计一个缓冲区(char *),将文件名拼接起来(sprintf)输出到缓冲区,之后检测文件是否存在(access)

如果存在则后缀加1,不存在直接创建即可

sprintf是字符串格式化输出的函数,百度连接,和printf用法差不多,只是将输出内容放到了字符串(Add_output)中

access是检测权限的一个函数,百度连接,返回值为0时文件不存在

mallocfree是c的动态分配函数,百度连接

Add_output = (char *)malloc(sizeof(char) *(strlen(Add_output_befor) + strlen(Add_output_after) + 15));

这句的作用是重新分配缓冲区的大小,让其值变成可被sprintf覆写的状态,malloc的用法请自行百度

注意使用后需要free

char *Add_output;
char *Add_output_befor = argv[2];
char *Add_output_after = argv[3];
for (int i = 0;; i++)
{
	Add_output = (char *)malloc(sizeof(char) *(strlen(Add_output_befor) + strlen(Add_output_after) + 15));

	sprintf(Add_output, "%s%d%s", Add_output_befor, i, Add_output_after);
	// puts(Add_output);
	if (access(Add_output, 0) != 0)
		break;
	else
		free(Add_output);
	if (i > 1000000)
	{
		printf("ERROR:output file name error\r\n");
	}
}
//puts(Add_output);

文件的打开与基本读写

使用fopen打开文件,fgetc读取单个字符,feof判断文件末尾,fputc输出内容到文件,fclose关闭文件

这几个函数很常用,不懂的请自行百度

思路:我们到这里已经将输出文件的位置和名字确定好了(上一步),

现在需要判断输入的文件是否可以打开,如果不打开则输出错误信息并退出

之后在打开输出文件,开始为读写做准备

输入文件使用只读模式打开,输出文件使用二进制写模式打开

char *Add_input = argv[1];
FILE *input_fp, *output_fp;
input_fp = fopen(Add_input, "r");
if (input_fp == NULL)
{
	printf("ERROR: failed to open the read file!\r\n");
	fclose(input_fp);
	fclose(output_fp);
	free(Add_output);
	system("pause");
	return 0;
}
output_fp = fopen(Add_output, "wb");
while (!feof(input_fp)) // 读文件
{
	data_zj = fgetc(input_fp);
    /*省略的内容*/
    fputc(data_all, output_fp);
}

格式转化(核心)

这是这个项目的核心,就是将ascii的字符解码成二进制的过程

我们先分析一下字符的样子

如下图,"B5 10 00 "由0-9和A-F来表示16进制的字符,以1Byte为单位,Byte直接用空格隔开

目标则是转化为 0xB5,0x10,0x00

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7ZUSOpEu-1675908462299)(picture/1.png)]

思路:

搞一个循环,知道读取到文件尾退出

首先读取一个字符,如果这个字符是空格则跳过这次循环,如果不是空格则再次判断是否到了文件尾(避免出现不合法的字符的情况),文件尾则退出循环

将这个字符转化为数,如Ascii 的’0’到’9’就减去’0’,'A’到’F’就减去’A’加10(0xA代表十进制的10).之后在读取一个字符,并对其转化

将两个字符按顺序拼接起来,输出到文件即可

while (!feof(input_fp)) // 读文件
{
	data_zj = fgetc(input_fp);
	if (data_zj == ' ')
		continue;
	if (feof(input_fp))
		break;
	data_first = Ascll2uchar(data_zj);
	data_last = Ascll2uchar(fgetc(input_fp));
	data_all = (data_first << 4) | data_last;
	// printf("%x ", data_all);
	fputc(data_all, output_fp);
}

时间计算

使用clock函数,在程序开头和结尾分别计算一次时间,相减即可

int begintime, endtime;
begintime = clock();
/*中间程序*/
endtime = clock();
printf("finish\r\nspend %d ms\r\n", endtime - begintime);

完整程序

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>

#define uint8_t unsigned char

uint8_t Ascll2uchar(uint8_t input)
{
    if (input >= 'a' && input <= 'z')
        return input - 'a' + 10;
    if (input >= 'A' && input <= 'Z')
        return input - 'A' + 10;
    if (input >= '0' && input <= '9')
        return input - '0';
}
int main(int argc, char *argv[])
{
    int begintime, endtime;
    uint8_t data_all, data_first, data_last;
    uint8_t data_zj;
    FILE *input_fp, *output_fp;

    char *Add_output;
    char *Add_input = argv[1];
    char *Add_output_befor = argv[2];
    char *Add_output_after = argv[3];
    // char *Add_input = "C:\\Users\\HZ12138\\Desktop\\1.txt";
    // char *Add_output_befor = "output";
    // char *Add_output_after = ".jpeg";
    begintime = clock();
    for (int i = 0;; i++)
    {
        Add_output = (char *)malloc(sizeof(char) *
                                    (strlen(Add_output_befor) + strlen(Add_output_after) + 15));

        sprintf(Add_output, "%s%d%s", Add_output_befor, i, Add_output_after);
        // puts(Add_output);
        if (access(Add_output, 0) != 0)
            break;
        else
            free(Add_output);
        if (i > 1000000)
        {
            printf("ERROR:output file name error\r\n");
        }
    }
    puts(Add_output);
    input_fp = fopen(Add_input, "r");
    if (input_fp == NULL)
    {
        printf("ERROR: failed to open the read file!\r\n");
        fclose(input_fp);
        fclose(output_fp);
        free(Add_output);
        system("pause");
        return 0;
    }
    output_fp = fopen(Add_output, "wb");
    while (!feof(input_fp)) // 读文件
    {
        data_zj = fgetc(input_fp);
        if (data_zj == ' ')
            continue;
        if (feof(input_fp))
            break;
        data_first = Ascll2uchar(data_zj);
        data_last = Ascll2uchar(fgetc(input_fp));
        data_all = (data_first << 4) | data_last;
        // printf("%x ", data_all);
        fputc(data_all, output_fp);
    }
    fclose(input_fp);
    fclose(output_fp);
    free(Add_output);
    endtime = clock();
    printf("finish\r\nspend %d ms\r\n", endtime - begintime);
    return 0;
}

批处理文件

使用批处理文件是为了方便的更改输出文件位置和文件名(记事本就能打开更改)

进入当前目录,打开exe文件

其中这个%1指的是获取拖拽到当前批处理上文件的绝对目录

@echo off
path = .\
Ascii2Bin.exe %1 output .jpeg
pause

使用教程

如下图,上面的是可执行文件(c语言编译出来的),中间的是批处理文件,下面的是要转化的文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HZLoRF20-1675908462300)(picture/4.png)]

我们将要转化的文件拖入批处理文件中,即可在当前目录生成解码后的文件,并输出信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RUnGOLPZ-1675908462301)(picture/5.png)]在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QvgIlzSW-1675908462303)(picture/6.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ur3T1hGZ-1675908462303)(picture/7.png)]

成品

GitHub

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
WinHex是一个专门用来对付各种日常紧急情况的小工具。它可以用来检查和修复各种文件、恢复删除文件、硬盘损坏造成的数据丢失等。同时它还可以让你看到其他程序隐藏起来的文件和数据。得到 ZDNetSoftwareLibrary 五星级最高评价,拥有强大的系统效用。   具体来说,WinHex 是一款以通用的 16 进制编辑器为核心,专门用来对付计算机取证、数据恢复、低级数据处理、以及 IT 安全性、各种日常紧急情况的高级工具: 用来检查和修复各种文件、恢复删除文件、硬盘损坏、数码相机卡损坏造成的数据丢失等。功能包括 (依照授权类型):   - 硬盘, 软盘, CD-ROM 和 DVD, ZIP, Smart Media, Compact Flash, 等磁盘编辑器...   - 支持 FAT, NTFS, Ext2/3, ReiserFS, Reiser4, UFS, CDFS, UDF 文件系统   - 支持对磁盘阵列 RAID 系统和动态磁盘的重组、分析和数据恢复   - 多种数据恢复技术   - 可分析 RAW 格式原始数据镜像文件中的完整目录结构,支持分段保存的镜像文件   - 数据解释器, 已知 20 种数据类型   - 使用模板编辑数据结构 (例如: 修复分区表/引导扇区)   - 连接和分割、以奇数偶数字节或字的方式合并、分解文件   - 分析和比较文件   - 搜索和替换功能尤其灵活   - 磁盘克隆 (可在 DOS 环境下使用 X-Ways Replica)   - 驱动器镜像和备份 (可选压缩或分割成 650 MB 的档案)   - 程序接口 (API) 和脚本   - 256 位 AES 加密, 校验和, CRC32, 哈希算法 (MD5, SHA-1, ...)   - 数据擦除功能,可彻底清除存储介质中残留数据   - 可导入剪贴板所有格式数据, 包括 ASCII、16 进制数据   - 可进行 2 进制、16 进制 ASCII, Intel 16 进制, 和 Motorola S 换   - 字符集: ANSI ASCII, IBM ASCII, EBCDIC, (Unicode)   - 立即窗口切换、打印、生成随机数字   - 支持打开大于 4 GB 的文件,非常快速,容易使用。   - 广泛的联机帮助
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值