Project reconstructed && Fix speed issue caused by excessive IO frequency && New information and progress bar output

This commit is contained in:
LuChiChick 2025-09-17 09:55:13 +08:00
parent 2b17809d07
commit e3571db925
12 changed files with 579 additions and 120 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
Build/
Test/

18
.vscode/c_cpp_properties.json vendored Normal file
View File

@ -0,0 +1,18 @@
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/Inc",
"${workspaceFolder}/**"
],
"defines": [
"UNICODE",
"_UNICODE"
],
"cStandard": "c17",
"cppStandard": "c++17"
}
],
"version": 4
}

18
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,18 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "[SNOOPerToCSV]构建并调试",
"type": "cppdbg",
"request": "launch",
"preLaunchTask": "project_debug_build_task", //
"program": "${workspaceFolder}\\Build\\Debug\\SNOOPerToCSV.exe", //
"args": [ //
],
"stopAtEntry": false,
"cwd": "${workspaceFolder}", //
"environment": [],
// "console": "externalTerminal",
}
]
}

17
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,17 @@
{
"tasks": [
{
"label": "project_debug_build_task", //Task
"type": "shell", //Task
"options": {
"cwd": "${workspaceFolder}" //
},
"command": "make", //
"args": [ //
"debug",
"-j4"
],
}
],
"version": "2.0.0"
}

10
Inc/Config.hpp Normal file
View File

@ -0,0 +1,10 @@
#ifndef __CONFIG_HPP__
#define __CONFIG_HPP__
// 进度条长度
#define PROGRESS_LENGTH 29
// 默认数值类型
#define DEFAULT_VALUE_TYPE "uint64_t"
#endif

13
Inc/Global_Variables.hpp Normal file
View File

@ -0,0 +1,13 @@
#ifndef __GLOBAL_VARIABLES_HPP__
#define __GLOBAL_VARIABLES_HPP__
#include "Type_Descriptions.hpp"
// 文件列表
extern file_node *file_list_head;
// 值列表
extern value_node *value_list_head;
// 起始时间戳
extern double time_begin;
#endif

25
Inc/Tool_Functions.hpp Normal file
View File

@ -0,0 +1,25 @@
#ifndef __TOOL_FUNCTIONS_HPP__
#define __TOOL_FUNCTIONS_HPP__
#include "Config.hpp"
extern "C"
{
#include "stdint.h"
#include "stdio.h"
#include "stdbool.h"
}
// 行进到上一行起始位置
size_t f_seek_pre_line_begin(FILE *file);
// 读取文件一行
size_t f_getline(FILE *file, char *buffer, const size_t buffer_len);
// 进度条打印
void progress_print(size_t completed, size_t total, bool reflush);
// 16进制字符串转十进制数值8字节
uint64_t hex_to_decimal(const char *str);
#endif

28
Inc/Type_Descriptions.hpp Normal file
View File

@ -0,0 +1,28 @@
#ifndef __TYPE_DESCRIPTIONS_HPP__
#define __TYPE_DESCRIPTIONS_HPP__
#include "Config.hpp"
extern "C"
{
#include "stdint.h"
}
// 文件链表节点
typedef struct file_node_struct
{
const char *file_name_str = nullptr;
file_node_struct *p_next = nullptr;
} file_node;
// 数据列表
typedef struct value_node_struct
{
char value_name_str[100] = {'\0'};
const char *value_type_str = "uint64_t";
uint64_t raw_value = 0x0000000000000000;
value_node_struct *p_next;
} value_node;
// 数据类型
#endif

223
Makefile Normal file
View File

@ -0,0 +1,223 @@
# 目标文件名称
TARGET_FILE_NAME = SNOOPerToCSV
# 编译目录
BUILD_DIR = Build
# Release 编译子目录
SUB_DIR_RELEASE = Release
# Debug 编译子目录
SUB_DIR_DEBUG = Debug
# Release 优化等级
RELEASE_OPT = -Os
# Debug 优化等级
DEBUG_OPT = -O0
# GUI或CUI编译选项 [0]CUI/Console [1]GUI
GUI = 0
# C编译标准
C_STD = c17
# C++编译标准
CXX_STD = c++17
# 源文件编码定义
INPUT_CHAR_ENCODING = UTF-8
# 编译产物单字节字符(char)编码定义
OUTPUT_CHAR_ENCODING = GBK
# 编译产物宽字符(wchar_t)编码定义
OUTPUT_WCHAR_ENCODING = UTF-16LE
# 编译工具前缀
COMPLIER_PREFIX = \
# C编译工具
C_COMPLIER = $(strip $(COMPLIER_PREFIX))gcc
# C++编译工具
C++_COMPLIER = $(strip $(COMPLIER_PREFIX))g++
# Windows 资源文件编译工具
WIN_RES_COMPLIER = windres
##################################################################################
# 链接库
LIB_LINK = \
# C定义
C_DEFS = \
_UNICODE \
UNICODE \
# C头文件目录
C_INCLUDES_PATHS = \
# C源文件目录
C_SOURCES_PATHS = \
# C额外单个源文件
C_EXTERA_SOURCES = \
# C++定义
CXX_DEFS = \
_UNICODE \
UNICODE \
# C++ 头文件目录
CXX_INCLUDES_PATHS = \
Inc \
# C++源文件目录
CXX_SOURCES_PATHS = \
Src \
# C++额外单个源文件
CXX_EXTERA_SOURCES = \
# Windows 资源文件脚本头文件路径
WIN_RESOURCE_INCLUDES_PATHS = \
# Windows 资源文件脚本列表
WIN_RESOURCE_SCRIPTS = \
##################################################################################
# C编译选项
CFLAGS = $(foreach text,$(C_DEFS),$(addprefix -D,$(text))) \
$(foreach path,$(C_INCLUDES_PATHS),$(addprefix -I,$(path))) \
-std=$(strip $(C_STD)) \
-finput-charset=$(strip $(INPUT_CHAR_ENCODING)) \
-fexec-charset=$(strip $(OUTPUT_CHAR_ENCODING)) \
-fwide-exec-charset=$(strip $(OUTPUT_WCHAR_ENCODING)) \
-static \
-Wall \
-MMD -MP -MF"$(@:%.o=%.d)" \
# C++编译选项
CXXFLAGS = $(foreach text,$(CXX_DEFS),$(addprefix -D,$(text))) \
$(foreach path,$(CXX_INCLUDES_PATHS),$(addprefix -I,$(path))) \
-std=$(strip $(CXX_STD)) \
-finput-charset=$(strip $(INPUT_CHAR_ENCODING)) \
-fexec-charset=$(strip $(OUTPUT_CHAR_ENCODING)) \
-fwide-exec-charset=$(strip $(OUTPUT_WCHAR_ENCODING)) \
-static \
-Wall \
-MMD -MP -MF"$(@:%.o=%.d)" \
-lstdc++ \
# 链接选项
LDFLAGS = -Wl,-Map,$(basename $@).map \
##################################################################################
# GUI与CUI选项附加
ifeq ($(GUI), 1)
LDFLAGS += -mwindows
else
LDFLAGS += -mconsole
endif
# C目标文件及索引目录关联
OBJECTS = $(notdir $(C_EXTERA_SOURCES:.c=.o))
OBJECTS += $(subst .c,.o,$(notdir $(foreach path,$(C_SOURCES_PATHS),$(wildcard $(path)/*.c))))
vpath %.c $(sort $(dir $(C_EXTERA_SOURCES))) $(sort $(C_SOURCES_PATHS))
# C++目标文件及索引目录关联
OBJECTS += $(notdir $(CXX_EXTERA_SOURCES:.cpp=.o))
OBJECTS += $(subst .cpp,.o,$(notdir $(foreach path,$(CXX_SOURCES_PATHS),$(wildcard $(path)/*.cpp))))
vpath %.cpp $(sort $(dir $(CXX_EXTERA_SOURCES))) $(sort $(CXX_SOURCES_PATHS))
# Windows资源文件及索引目录关联
OBJECTS += $(notdir $(WIN_RESOURCE_SCRIPTS:.rc=.o))
vpath %.rc $(sort $(dir $(WIN_RESOURCE_SCRIPTS)))
# Release 目标文件
RELEASE_OBJECTS = $(addprefix $(BUILD_DIR)/$(SUB_DIR_RELEASE)/,$(OBJECTS))
# Debug 目标文件
DEBUG_OBJECTS = $(addprefix $(BUILD_DIR)/$(SUB_DIR_DEBUG)/,$(OBJECTS))
##################################################################################
# all任务 目标为 release 和 debug 产物
all: $(BUILD_DIR)/$(SUB_DIR_RELEASE)/$(TARGET_FILE_NAME).exe $(BUILD_DIR)/$(SUB_DIR_DEBUG)/$(TARGET_FILE_NAME).exe
@echo ====== [All] Build Procedure Accomplished ======
# release任务 目标为 release 产物
release: $(BUILD_DIR)/$(SUB_DIR_RELEASE)/$(TARGET_FILE_NAME).exe
@echo ====== [Release] Build Procedure Accomplished ======
# debug任务 目标为 debug 产物
debug: $(BUILD_DIR)/$(SUB_DIR_DEBUG)/$(TARGET_FILE_NAME).exe
@echo ====== [Debug] Build Procedure Accomplished ======
# 清理任务
clean: $(BUILD_DIR)
powershell rm -r $(BUILD_DIR)
# 构建目录生成
$(BUILD_DIR):
powershell mkdir $@
# Release 工作目录生成
$(BUILD_DIR)/$(SUB_DIR_RELEASE): | $(BUILD_DIR)
powershell mkdir $@
# Debug 工作目录生成
$(BUILD_DIR)/$(SUB_DIR_DEBUG): | $(BUILD_DIR)
powershell mkdir $@
# Release 最终可执行文件编译任务
$(BUILD_DIR)/$(SUB_DIR_RELEASE)/$(TARGET_FILE_NAME).exe: $(RELEASE_OBJECTS)
@echo ====== [Release] All File Compiled. Now Linking... ======
$(C++_COMPLIER) $(RELEASE_OBJECTS) -static -o $@ $(LIB_LINK) $(LDFLAGS)
@echo ====== [Release] Program Link Finished ======
# Debug 最终可执行文件编译任务
$(BUILD_DIR)/$(SUB_DIR_DEBUG)/$(TARGET_FILE_NAME).exe: $(DEBUG_OBJECTS)
@echo ====== [Debug] All File Compiled. Now Linking... ======
$(C++_COMPLIER) $(DEBUG_OBJECTS) -static -o $@ $(LIB_LINK) $(LDFLAGS)
@echo ====== [Debug] Program Link Finished ======
# C Release 目标文件编译
$(BUILD_DIR)/$(SUB_DIR_RELEASE)%.o: %.c Makefile | $(BUILD_DIR)/$(SUB_DIR_RELEASE)
@echo ====== [Release] C Source File "$<" Compiling... ======
$(C_COMPLIER) -c $(CFLAGS) $(RELEASE_OPT) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(SUB_DIR_RELEASE)/$(notdir $(<:.c=.lst)) $< -o $@
# C++ Release 目标文件编译
$(BUILD_DIR)/$(SUB_DIR_RELEASE)/%.o: %.cpp Makefile | $(BUILD_DIR)/$(SUB_DIR_RELEASE)
@echo ====== [Release] C++ Source File "$<" Compiling... ======
$(C++_COMPLIER) -c $(CXXFLAGS) $(RELEASE_OPT) -Wa,-a,-ad,-ahlms=$(BUILD_DIR)/$(SUB_DIR_RELEASE)/$(notdir $(<:.cpp=.lst)) $< -o $@
# Release 资源脚本文件编译
$(BUILD_DIR)/$(SUB_DIR_RELEASE)/%.o: %.rc Makefile | $(BUILD_DIR)/$(SUB_DIR_RELEASE)
@echo ====== [Release] Windows Resource Script File "$<" Compiling... ======
$(WIN_RES_COMPLIER) $(foreach path,$(WIN_RESOURCE_INCLUDES_PATHS),$(addprefix -I,$(path))) $< -o $@
# C Debug 目标文件编译
$(BUILD_DIR)/$(SUB_DIR_DEBUG)%.o: %.c Makefile | $(BUILD_DIR)/$(SUB_DIR_DEBUG)
@echo ====== [Debug] C Source File "$<" Compiling... ======
$(C_COMPLIER) -c $(CFLAGS) $(DEBUG_OPT) -g -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(SUB_DIR_DEBUG)/$(notdir $(<:.c=.lst)) $< -o $@
# C++ Debug 目标文件编译
$(BUILD_DIR)/$(SUB_DIR_DEBUG)/%.o: %.cpp Makefile | $(BUILD_DIR)/$(SUB_DIR_DEBUG)
@echo ====== [Debug] C++ Source File "$<" Compiling... ======
$(C++_COMPLIER) -c $(CXXFLAGS) $(DEBUG_OPT) -g -Wa,-a,-ad,-ahlms=$(BUILD_DIR)/$(SUB_DIR_DEBUG)/$(notdir $(<:.cpp=.lst)) $< -o $@
# Debug 资源脚本文件编译
$(BUILD_DIR)/$(SUB_DIR_DEBUG)/%.o: %.rc Makefile | $(BUILD_DIR)/$(SUB_DIR_DEBUG)
@echo ====== [Debug] Windows Resource Script File "$<" Compiling... ======
$(WIN_RES_COMPLIER) $(foreach path,$(WIN_RESOURCE_INCLUDES_PATHS),$(addprefix -I,$(path))) $< -o $@
# 依赖关系
-include $(RELEASE_OBJECTS:.o=.d)
-include $(DEBUG_OBJECTS:.o=.d)

8
Src/Global_Variables.cpp Normal file
View File

@ -0,0 +1,8 @@
#include "Global_Variables.hpp"
// 文件列表
file_node *file_list_head = nullptr;
// 值列表
value_node *value_list_head = nullptr;
// 起始时间戳
double time_begin = 0.0;

View File

@ -1,3 +1,6 @@
#include "Tool_Functions.hpp"
#include "Global_Variables.hpp"
extern "C" extern "C"
{ {
#include "stdio.h" #include "stdio.h"
@ -7,117 +10,6 @@ extern "C"
#include "ctype.h" #include "ctype.h"
} }
// 行进到上一行起始位置
size_t f_seek_pre_line_begin(FILE *file)
{
int count = 0;
// 本身就在文件起始位置
if (ftell(file) == 0)
return 0;
// 本身在文件结尾
if (fgetc(file) == EOF)
{
// 移动到之前
do
{
fseek(file, -2, SEEK_CUR);
count--;
} while (ftell(file) != 0 && fgetc(file) != '\n');
return count;
}
// 其它情况返
// 移动到上一行的结尾处
while (ftell(file) != 0 && fgetc(file) != '\n')
{
fseek(file, -2, SEEK_CUR);
count--;
}
fseek(file, -2, SEEK_CUR);
count--;
// 移动到上上一行的结尾处
while (ftell(file) != 0 && fgetc(file) != '\n')
{
fseek(file, -2, SEEK_CUR);
count--;
}
return count;
}
// 读取一行
size_t f_getline(FILE *file, char *buffer, size_t buffer_len)
{
memset(buffer, '\0', buffer_len);
int count = 0;
while (true)
{
if (count >= buffer_len)
{
fseek(file, -count, SEEK_CUR);
memset(buffer, '\0', buffer_len);
return 0;
}
char ch = fgetc(file);
if (ch == EOF && count == 0)
return 0;
if (ch == '\n' || ch == EOF)
{
buffer[count] = ch;
return count + 1;
}
buffer[count] = ch;
count++;
}
}
// 16进制字符串转十进制数值8字节
uint64_t hex_to_decimal(const char *str)
{
uint64_t value = 0;
int len = strlen(str);
// 循环读取
for (int count = 0; count < len; count++)
{
value *= 16;
if (str[count] >= '0' && str[count] <= '9')
value += str[count] - '0';
else
value += toupper(str[count]) - 'A' + 10;
}
return value;
}
// 文件链表节点
typedef struct file_node_struct
{
const char *file_name_str = nullptr;
file_node_struct *p_next = nullptr;
} file_node;
// 数据列表
typedef struct value_node_struct
{
char value_name_str[100] = {'\0'};
uint64_t raw_value = 0x0000000000000000;
value_node_struct *p_next;
} value_node;
// 文件列表
file_node *file_list_head = nullptr;
value_node *value_list_head = nullptr;
double time_begin = 0.0;
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
// 处理指令输入 // 处理指令输入
@ -136,6 +28,11 @@ int main(int argc, char *argv[])
continue; continue;
} }
// 处理格式串指令
{
}
// 其余输入作为文件输入
static file_node *target_node = nullptr; static file_node *target_node = nullptr;
if (file_list_head == nullptr) if (file_list_head == nullptr)
{ {
@ -153,9 +50,11 @@ int main(int argc, char *argv[])
target_node->p_next = nullptr; target_node->p_next = nullptr;
} }
target_node->file_name_str = argv[count]; target_node->file_name_str = argv[count];
printf("%s\n", argv[count]); // printf("%s\n", argv[count]);
} }
printf("\n\n");
// 遍历文件 // 遍历文件
file_node *target_file_node = file_list_head; file_node *target_file_node = file_list_head;
while (target_file_node != nullptr) while (target_file_node != nullptr)
@ -171,14 +70,28 @@ int main(int argc, char *argv[])
output_file = fopen(buffer, "wb"); output_file = fopen(buffer, "wb");
} }
if (input_file == nullptr || output_file == nullptr)
{
target_file_node = target_file_node->p_next;
continue;
}
printf("Solving file: \"%s\"\n", target_file_node->file_name_str);
printf("----------------------------------------------------------------\n");
printf("%-40s %-16s %s\n", "Value Name", "Out Type", "ID");
printf("----------------------------------------------------------------\n");
char segment_buffer[1000] = {'\0'}; char segment_buffer[1000] = {'\0'};
size_t total_line;
// 跳过非数据行 // 跳过非数据行
while (true) while (true)
{ {
f_getline(input_file, segment_buffer, sizeof(segment_buffer)); f_getline(input_file, segment_buffer, sizeof(segment_buffer));
if (segment_buffer[0] == '-') if (segment_buffer[0] == '-')
{ {
sscanf(segment_buffer + 1, "%zu", &total_line);
f_seek_pre_line_begin(input_file); f_seek_pre_line_begin(input_file);
break; break;
} }
@ -189,6 +102,7 @@ int main(int argc, char *argv[])
// 分配数值链表节点 // 分配数值链表节点
value_list_head = (value_node *)malloc(sizeof(value_node)); value_list_head = (value_node *)malloc(sizeof(value_node));
value_list_head->p_next = nullptr; value_list_head->p_next = nullptr;
value_list_head->value_type_str = DEFAULT_VALUE_TYPE;
value_list_head->raw_value = 0x0000000000000000; value_list_head->raw_value = 0x0000000000000000;
memset(value_list_head->value_name_str, '\0', sizeof(value_list_head->value_name_str)); memset(value_list_head->value_name_str, '\0', sizeof(value_list_head->value_name_str));
@ -205,7 +119,7 @@ int main(int argc, char *argv[])
value_list_head->raw_value = hex_to_decimal(value_str); value_list_head->raw_value = hex_to_decimal(value_str);
} }
// 处理第一个数值循环 // 处理第一个数值循环记录
{ {
value_node *target_value_node = value_list_head; value_node *target_value_node = value_list_head;
while (true) while (true)
@ -222,18 +136,28 @@ int main(int argc, char *argv[])
// 完成回环 // 完成回环
if (!strcmp(value_name_str, value_list_head->value_name_str)) if (!strcmp(value_name_str, value_list_head->value_name_str))
{ {
// 回转到文件的第二行 // 回转到文件的数据行起始位置
memset(segment_buffer, '\0', sizeof(segment_buffer)); memset(segment_buffer, '\0', sizeof(segment_buffer));
fseek(input_file, 0, SEEK_SET); fseek(input_file, 0, SEEK_SET);
// 跳过非数据行
while (true)
{
f_getline(input_file, segment_buffer, sizeof(segment_buffer)); f_getline(input_file, segment_buffer, sizeof(segment_buffer));
if (segment_buffer[0] == '-')
{
sscanf(segment_buffer + 1, "%zu", &total_line);
f_seek_pre_line_begin(input_file);
break;
}
}
break; break;
} }
// 未完成回环,记录新的类型 // 未完成回环,分配数值链表节点
// 分配数值链表节点
target_value_node->p_next = (value_node *)malloc(sizeof(value_node)); target_value_node->p_next = (value_node *)malloc(sizeof(value_node));
target_value_node = target_value_node->p_next; target_value_node = target_value_node->p_next;
target_value_node->p_next = nullptr; target_value_node->p_next = nullptr;
target_value_node->value_type_str = DEFAULT_VALUE_TYPE;
target_value_node->raw_value = 0x0000000000000000; target_value_node->raw_value = 0x0000000000000000;
memset(target_value_node->value_name_str, '\0', sizeof(target_value_node->value_name_str)); memset(target_value_node->value_name_str, '\0', sizeof(target_value_node->value_name_str));
@ -243,6 +167,18 @@ int main(int argc, char *argv[])
} }
} }
// 展示数据类型输出
{
value_node *target_value_node = value_list_head;
size_t value_count = 0;
while (target_value_node != nullptr)
{
printf("%-40s %-16s [%d]\n", target_value_node->value_name_str, target_value_node->value_type_str, value_count++);
target_value_node = target_value_node->p_next;
}
}
// 输出csv抬头部分 // 输出csv抬头部分
{ {
value_node *target_value_node = value_list_head; value_node *target_value_node = value_list_head;
@ -257,7 +193,10 @@ int main(int argc, char *argv[])
// 循环处理数据 // 循环处理数据
{ {
printf("----------------------------------------------------------------\n");
memset(segment_buffer, '\0', sizeof(segment_buffer)); memset(segment_buffer, '\0', sizeof(segment_buffer));
size_t line_count = -1;
while (f_getline(input_file, segment_buffer, sizeof(segment_buffer)) != 0) while (f_getline(input_file, segment_buffer, sizeof(segment_buffer)) != 0)
{ {
char value_name_str[100] = {'\0'}; char value_name_str[100] = {'\0'};
@ -279,7 +218,10 @@ int main(int argc, char *argv[])
timestamp += time; timestamp += time;
} }
printf("timestamp: %lfs %s\n", timestamp, segment_buffer); line_count++;
if ((line_count % 10000) == 0)
progress_print(line_count, total_line, true);
// printf("timestamp: %lfs %s\n", timestamp, segment_buffer);
// 处理数值链表 // 处理数值链表
value_node *target_value_node = value_list_head; value_node *target_value_node = value_list_head;
@ -290,8 +232,15 @@ int main(int argc, char *argv[])
if (!strcmp(value_name_str, target_value_node->value_name_str)) if (!strcmp(value_name_str, target_value_node->value_name_str))
target_value_node->raw_value = hex_to_decimal(value_str); target_value_node->raw_value = hex_to_decimal(value_str);
// 输出当前值 // 特殊处理
fprintf(output_file, ",%d", target_value_node->raw_value + 0); if (strstr(target_value_node->value_name_str, "wmrmeasured_speed"))
{
float *value = (float *)&(target_value_node->raw_value);
fprintf(output_file, ",%f", *value);
}
else
fprintf(output_file, ",%llu", target_value_node->raw_value);
target_value_node = target_value_node->p_next; target_value_node = target_value_node->p_next;
} }
fprintf(output_file, "\n"); fprintf(output_file, "\n");
@ -299,6 +248,13 @@ int main(int argc, char *argv[])
// 清理缓冲区 // 清理缓冲区
memset(segment_buffer, '\0', sizeof(segment_buffer)); memset(segment_buffer, '\0', sizeof(segment_buffer));
} }
progress_print(line_count, total_line, true);
printf("\n\n\n");
}
// 清理数据列表
{
} }
target_file_node = target_file_node->p_next; target_file_node = target_file_node->p_next;

141
Src/Tool_Functions.cpp Normal file
View File

@ -0,0 +1,141 @@
#include "Tool_Functions.hpp"
extern "C"
{
#include "string.h"
#include "ctype.h"
}
// 行进到上一行起始位置
size_t f_seek_pre_line_begin(FILE *file)
{
int count = 0;
// 本身就在文件起始位置
if (ftell(file) == 0)
return 0;
// 本身在文件结尾
if (fgetc(file) == EOF)
{
// 移动到之前
do
{
fseek(file, -2, SEEK_CUR);
count--;
} while (ftell(file) != 0 && fgetc(file) != '\n');
return count;
}
// 其它情况
// 移动到上一行的结尾处(回到本行起始位置)
while (ftell(file) != 0 && fgetc(file) != '\n')
{
fseek(file, -2, SEEK_CUR);
count--;
}
// 移动到上上一行的结尾处
do
{
fseek(file, -2, SEEK_CUR);
count--;
} while (ftell(file) != 0 && fgetc(file) != '\n');
return count;
}
// 读取文件一行
size_t f_getline(FILE *file, char *buffer, const size_t buffer_len)
{
if (buffer == nullptr || file == nullptr)
return 0;
memset(buffer, '\0', buffer_len);
size_t count = 0;
// 循环读取
while (true)
{
// 超长判定
if (count + 1 == buffer_len)
return buffer_len;
// 正常读取
char ch = fgetc(file);
// 仅文件结尾时
if (ch == EOF && count == 0)
return 0;
// 成功换行
if (ch == '\n')
{
buffer[count] = '\n';
return count + 1;
}
// 没有换行但是遇到了文件结尾
if (ch == EOF)
{
buffer[count] = '\n';
return count;
}
// 其它情况下正常复制
buffer[count] = ch;
count++;
}
}
// 进度条打印
void progress_print(size_t completed, size_t total, bool reflush)
{
// 消除单行内容
if (reflush)
putchar('\r');
else
putchar('\n');
double p_percent = 1.0 * completed / total;
putchar('[');
// 输出完成部分填充
size_t completed_count = (PROGRESS_LENGTH * p_percent) - 1;
if (p_percent - (int)(p_percent) > 0.5)
completed_count++;
for (int count = completed_count; count > 0; count--)
putchar('=');
putchar('>');
// 填充未完成部分
for (int count = PROGRESS_LENGTH - (completed_count + 1); count > 0; count--)
putchar(' ');
putchar(']');
// 进度数显
printf(" %d/%d (%%%.2lf)", completed, total, p_percent * 100);
}
// 16进制字符串转十进制数值8字节
uint64_t hex_to_decimal(const char *str)
{
uint64_t value = 0;
int len = strlen(str);
// 循环读取
for (int count = 0; count < len; count++)
{
value *= 16;
if (str[count] >= '0' && str[count] <= '9')
value += str[count] - '0';
else
value += toupper(str[count]) - 'A' + 10;
}
return value;
}