C语言路线数据处理疑问:读取文件首数字且不写入二进制文件
问题解决:C语言路线数据处理程序优化
需求回顾
- 处理.txt文件中的路线结构体数组,结构体包含起点(30字符)、终点(30字符)、路线编号
- 将数据按路线编号排序后写入二进制文件
- 用户输入编号后,仅加载对应路线到内存,输出起点和终点
- 当前困惑:无法读取.txt首行的记录数,且不将该数值写入二进制文件
解决方案代码
步骤说明
- 读取txt首行的记录数,用于后续读取结构体数据
- 读取所有路线数据到临时数组,排序后写入二进制文件(仅写入结构体数据,不包含记录数)
- 查询时,利用二进制文件的随机访问特性,遍历查找目标编号,找到后仅加载该结构体到内存
完整代码
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <string.h> // 路线结构体定义 struct MARSH { char startOfRoute[30]; char finalOfRoute[30]; unsigned int routeNumber; }; // 排序函数:按路线编号升序 void sortRoutes(struct MARSH* routes, int count) { struct MARSH temp; for (int i = 0; i < count - 1; i++) { for (int j = i + 1; j < count; j++) { if (routes[j].routeNumber < routes[i].routeNumber) { temp = routes[i]; routes[i] = routes[j]; routes[j] = temp; } } } } // 从二进制文件查找目标路线,找到后加载到传入的结构体指针 bool findRouteFromBin(unsigned int targetNum, FILE* binFile, struct MARSH* result) { struct MARSH temp; // 文件指针移到开头 fseek(binFile, 0, SEEK_SET); // 逐个读取结构体,直到文件结束 while (fread(&temp, sizeof(struct MARSH), 1, binFile) == 1) { if (temp.routeNumber == targetNum) { // 找到后复制到结果结构体,仅加载该数据到内存 memcpy(result, &temp, sizeof(struct MARSH)); return true; } } return false; } int main() { FILE* txtFile = fopen("routes.txt", "r"); if (!txtFile) { perror("Failed to open txt file"); return 1; } // 读取txt首行的记录数 int recordCount; if (fscanf(txtFile, "%d", &recordCount) != 1) { perror("Failed to read record count"); fclose(txtFile); return 1; } // 跳过首行剩余的换行符,避免影响后续fgets fgetc(txtFile); // 动态分配内存存储所有路线(仅在转换阶段使用) struct MARSH* allRoutes = malloc(recordCount * sizeof(struct MARSH)); if (!allRoutes) { perror("Failed to allocate memory"); fclose(txtFile); return 1; } // 读取txt中的路线数据 for (int i = 0; i < recordCount; i++) { // 读取起点 fgets(allRoutes[i].startOfRoute, 30, txtFile); // 去掉fgets读取的换行符 allRoutes[i].startOfRoute[strcspn(allRoutes[i].startOfRoute, "\n")] = '\0'; // 读取终点 fgets(allRoutes[i].finalOfRoute, 30, txtFile); allRoutes[i].finalOfRoute[strcspn(allRoutes[i].finalOfRoute, "\n")] = '\0'; // 读取路线编号 fscanf(txtFile, "%u", &allRoutes[i].routeNumber); // 跳过编号后的换行符 fgetc(txtFile); } fclose(txtFile); // 按路线编号排序 sortRoutes(allRoutes, recordCount); // 写入二进制文件(仅写入结构体数据,不包含记录数) FILE* binFile = fopen("routes.bin", "wb"); if (!binFile) { perror("Failed to open binary file"); free(allRoutes); return 1; } fwrite(allRoutes, sizeof(struct MARSH), recordCount, binFile); fclose(binFile); // 转换完成后释放临时内存 free(allRoutes); // 用户查询阶段 unsigned int routeChoice; printf("Enter the route number you need information about: "); scanf("%u", &routeChoice); // 打开二进制文件准备查询 binFile = fopen("routes.bin", "rb"); if (!binFile) { perror("Failed to open binary file for query"); return 1; } struct MARSH targetRoute; bool found = findRouteFromBin(routeChoice, binFile, &targetRoute); fclose(binFile); if (!found) { printf("\nThere is no such route number.\n"); } else { printf("\nStarting point of the route: %s\n", targetRoute.startOfRoute); printf("The final destination of the route: %s\n", targetRoute.finalOfRoute); } return 0; }
关键细节说明
- 读取txt首行记录数:用
fscanf读取首行数字后,必须用fgetc跳过换行符,否则后续fgets会读取空行 - 不写入记录数到二进制文件:写入时直接将排序后的结构体数组写入,不额外写入记录数值
- 仅加载目标路线到内存:查询时逐个读取二进制文件中的结构体,找到目标后仅复制该结构体到内存,无需加载整个数组
- 动态内存分配:避免固定数组大小限制,根据txt中的记录数分配内存
内容的提问来源于stack exchange,提问作者GRIMM
相关产品推荐
相关产品推荐

