網站首頁 編程語言 正文
本文中的代碼可以將文件中的十六進制存儲與二進制存儲相互轉換。
十六進制->二進制
原理是:每兩位存儲為一個字符(char)保存。
因為十六進制數最大為 f,即 15,在內存中只需要 4 位就可以表示。而一般情況下一個字符是占一個字節 8 位,所以正好可以存儲十六進制兩位。
舉個栗子:
在文件中存儲十六進制為ab,ab轉換為二進制,就是1010 1011,剛好八位,可以聯想到ASCII碼,用一個字符可以表示。
注意轉為二進制后,前32個為不可見字符,附圖ASCII碼。
(將十六進制轉為二進制還會壓縮一倍的空間?因為ab本來占兩個字節,現在轉成二進制,即一個char字符,只占用一個字節大小。但是轉換過程中時間消耗,我不太確定是否優化了)
#include <stdio.h>
int main() {
FILE * in = fopen("./data.txt", "r");
FILE * out = fopen("./data", "w");
while (1) {
char c;
unsigned char d = 0;
for (int i = 0; i < 2; ++i) {
// 從 in 讀取 1 個大小為 1 字節數據保存在 c
if (fread(&c, 1, 1, in) == 0) {
fclose(in);
fclose(out);
return 0;
}
// 讀到空格或者換行索引需要回退
if (c == ' ' || c == '\n') {
i--;
continue;
}
// 將讀到的十六進制字符轉成具體的十進制數字
if (c >= '0' && c <= '9') {
c -= '0';
} else if (c >= 'a' && c <= 'f') {
c -= 'a';
c += 10;
} else {
printf("error");
}
//printf("c -> %d \n", c);
d <<= 4;
d |= c;
}
//printf("-------> %c\n", d);
fwrite(&d, 1, 1, out);
}
return 0;
}
核心代碼:
d <<= 4 and d |= c
解釋:
內層for循環為兩次,c讀取兩次:
我們假設第一次讀到a字符,第二次讀到b字符。
(或運算:參加運算的兩個對象只要有一個為1,其值為1)
操作 | 值 |
---|---|
第一次循環開始 : | d (0000 0000) c(0000 1010) |
d <<= 4 : | d (0000 0000) ? ? c(0000 1010) |
d |= c : | d (0000 1010) c(0000 1010) |
第二次循環開始: | d (0000 1010) c(0000 1011) |
d <<= 4 :? | d (1010 0000) ? ? c(0000 1011) |
d |= c :? | d (1010 1011) c(0000 1011) |
兩次循環結束 將d寫入文件,轉換完成。 | ? |
如果想知道轉換是否正確的話,可以用 hexdump -C + 文件名(data) 檢查一下是否正確。(linux命令)
二進制->十六進制
這個就是上邊操作相反的過程,讀取二進制文件,然后轉成十六進制字符保存。
#include <stdio.h>
int main() {
FILE * in = fopen("./data.txt", "r");
FILE * out = fopen("./data", "w");
char space = ' ';
char enter = '\n';
int idx = 0;
while (1) {
char c[2];
unsigned char d = 0;
for (int i = 0; i < 4; ++i) {
// 讀取一個字節
if (fread(&d, 1, 1, in) == 0) {
fclose(in);
fclose(out);
return 0;
}
// 一個二進制字節轉回兩個十六進制字符
char mask = 0xf;
c[0] = d >> 4; // 將低位移走就是該字節保存的第一個十六進制字符
c[1] = d & mask; // 保留 d 的低位就是該字節保存的第二個十六進制字符
// 將十進制數字轉回對應的十六進制字符(與上一步轉換的代碼相反)
if (c[0] >= 0 && c[0] <= 9) {
c[0] += '0';
} else {
c[0] -= 10;
c[0] += 'a';
}
if (c[1] >= 0 && c[1] <= 9) {
c[1] += '0';
} else {
c[1] -= 10;
c[1] += 'a';
}
// 從 c 地址開始讀取兩個字節,寫到 out
fwrite(&c, 1, 2, out);
}
// 寫空格或者換行 保持格式
idx++;
if (idx == 4){
idx = 0;
fwrite(&enter, 1, 1, out);
} else {
fwrite(&space, 1, 1, out);
}
}
return 0;
}
mask的二進制是0000 1111。
原文鏈接:https://blog.csdn.net/weixin_43786143/article/details/127725926
相關推薦
- 2022-08-29 如何用python將單引號替換為雙引號_python
- 2022-05-10 console.log() 與 console.dir() 的區別:
- 2022-06-18 Android實現背景圖滑動變大松開回彈效果_Android
- 2022-10-14 Go?Ginrest實現一個RESTful接口_Golang
- 2022-11-23 解決vant組件van-list 首屏加載兩次的情況
- 2022-05-03 C#面向對象設計原則之里氏替換原則_C#教程
- 2022-07-01 C++中strlen函數的三種實現方法_C 語言
- 2023-03-21 C++中如何將operator==定義為類的成員函數_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支