汽车租赁程序取消预约功能异常:CSV数据错乱与空行问题
汽车租赁取消预约功能问题修复
问题描述
- 初始文件空行问题:
rented_cars.csv开头出现异常空行,内容如下:
,,,, 3,123456Z,Tue May 07 01:00:00 2024,Wed May 08 01:00:00 2024,200.00$ 3,789123B,Tue May 07 01:00:00 2024,Wed May 08 01:00:00 2024,100.00$
- 取消预约后日期异常:用户3取消车牌为123456Z的预约后,文件中日期变为1970年初始时间,格式错乱:
,,,Thu Jan 01 02:00:07 1970, 3,789123B,Thu Jan 01 02:00:00 1970, Thu Jan 01 02:00:07 1970,
问题根源分析
1. 初始空行与CSV格式问题
appendRentInfoToCSV函数中错误地对字符串类型的TotalPriceForTheRent使用fixed << setprecision(2)数值格式化符,导致输出异常,可能产生空字段或乱码。- 文件打开模式使用
ios::out | ios::app,ios::out的截断逻辑与ios::app追加逻辑冲突,可能导致写入行为异常。
2. 取消后日期变1970问题
cancelRESERVATION函数仅从文件读取预约信息用于显示,但未将文件中的日期字符串解析为time_t类型更新到rents数组,导致数组中RentStartDate和RentEndDate字段未初始化(值为0),转换后对应1970年初始时间。
修复方案
1. 修复CSV写入格式问题
修改appendRentInfoToCSV函数,移除无效的数值格式化符,调整文件打开模式:
void appendRentInfoToCSV(const RentInformation& rentInfo) { // 仅使用ios::app实现追加写入,避免截断冲突 ofstream outputFile("C:\\Users\\User\\Desktop\\rented_cars.csv", ios::app); if (outputFile.is_open()) { char startDateStr[50]; char endDateStr[50]; strftime(startDateStr, sizeof(startDateStr), "%a %b %d %H:%M:%S %Y", localtime(&rentInfo.RentStartDate)); strftime(endDateStr, sizeof(endDateStr), "%a %b %d %H:%M:%S %Y", localtime(&rentInfo.RentEndDate)); // 移除针对字符串的数值格式化符,直接输出字符串 outputFile << rentInfo.ClientID << ',' << rentInfo.CarPlateNumber << ',' << startDateStr << ',' << endDateStr << ',' << rentInfo.TotalPriceForTheRent << endl; cout << "Reservation information added successfully." << endl; outputFile.close(); } else { cerr << "Failed to open file for writing." << endl; } }
2. 修复日期同步问题
添加日期字符串转time_t的辅助函数,并在cancelRESERVATION中同步加载文件数据到rents数组:
辅助函数:字符串转时间戳
time_t stringToTime(const string& dateStr) { struct tm tm = {}; // 匹配CSV中的日期格式 strptime(dateStr.c_str(), "%a %b %d %H:%M:%S %Y", &tm); return mktime(&tm); }
修改取消预约函数
void cancelRESERVATION(CarsInformation cars[], int& numCars, RentInformation rents[], int& numRents, UserInformation users[], int& numUsers, string userID) { ifstream inputFile("C:\\Users\\User\\Desktop\\rented_cars.csv"); if (!inputFile.is_open()) { cerr << "Failed to open file for reading." << endl; return; } bool hasReservations = false; int j = 1; string line; // 清空数组,重新从文件加载最新数据 numRents = 0; while (getline(inputFile, line)) { stringstream ss(line); string field; string fields[5]; int fieldIndex = 0; while (getline(ss, field, ',')) { if (fieldIndex < 5) { fields[fieldIndex++] = field; } } // 跳过空行或格式错误的行 if (fieldIndex != 5 || fields[0].empty()) { continue; } // 将文件数据解析到rents数组 RentInformation rent; rent.ClientID = fields[0]; rent.CarPlateNumber = fields[1]; rent.RentStartDate = stringToTime(fields[2]); rent.RentEndDate = stringToTime(fields[3]); rent.TotalPriceForTheRent = fields[4]; rents[numRents++] = rent; if (fields[0] == userID) { cout << "Car #" << j++ << endl; cout << "Plate Number: " << fields[1] << endl; cout << "Start Date: " << fields[2] << endl; cout << "End Date: " << fields[3] << endl; cout << "Total Price: " << fields[4] << endl; hasReservations = true; } } inputFile.close(); if (!hasReservations) { cout << "You have no reservations to cancel." << endl; return; } string plateNumber; cout << "Enter the plate number of the car you want to cancel the reservation for: "; cin >> plateNumber; int index = -1; for (int i = 0; i < numRents; i++) { if (rents[i].CarPlateNumber == plateNumber && rents[i].ClientID == userID) { index = i; break; } } if (index != -1) { // 移除指定预约记录 for (int i = index; i < numRents - 1; i++) { rents[i] = rents[i + 1]; } numRents--; // 更新车辆可用性 for (int i = 0; i < numCars; i++) { if (cars[i].plateNumber == plateNumber) { cars[i].availability = "available"; break; } } // 写入cars.csv ofstream outputFile("C:\\Users\\User\\Desktop\\cars.csv"); if (outputFile.is_open()) { for (int i = 0; i < numCars; i++) { outputFile << cars[i].type << ',' << cars[i].brand << ',' << cars[i].model << ',' << cars[i].year << ',' << cars[i].subType << ',' << cars[i].color << ',' << cars[i].plateNumber << ',' << cars[i].price << ',' << cars[i].availability << endl; } outputFile.close(); cout << "Car availability updated successfully." << endl; } else { cerr << "Failed to open file for writing." << endl; } // 写入rented_cars.csv,移除无效格式化符 ofstream outputFile2("C:\\Users\\User\\Desktop\\rented_cars.csv"); if (outputFile2.is_open()) { for (int i = 0; i < numRents; i++) { char startDateStr[50]; char endDateStr[50]; strftime(startDateStr, sizeof(startDateStr), "%a %b %d %H:%M:%S %Y", localtime(&rents[i].RentStartDate)); strftime(endDateStr, sizeof(endDateStr), "%a %b %d %H:%M:%S %Y", localtime(&rents[i].RentEndDate)); outputFile2 << rents[i].ClientID << ',' << rents[i].CarPlateNumber << ',' << startDateStr << ',' << endDateStr << ',' << rents[i].TotalPriceForTheRent << endl; } outputFile2.close(); cout << "Updated reservation information written to the CSV file." << endl; } else { cerr << "Failed to open file for writing." << endl; } cout << "Reservation canceled successfully." << endl; } else { cout << "Reservation not found for the provided plate number." << endl; } }
额外注意事项
- 确保
rents数组有足够存储空间,避免越界; - 可添加
strptime解析失败的错误处理(如返回0时提示日期格式错误); - 历史遗留的空行可手动删除,修复后的代码会自动跳过格式错误的行。
内容的提问来源于stack exchange,提问作者Elie ISSA
相关产品推荐
相关产品推荐

