Tôi mới làm quen với lập trình và cần trợ giúp với dự án C của mình. Tôi phải tìm kiếm một thành phố, xác nhận rằng nó tồn tại trong tệp đầu tiên (city.csv), sau đó lấy ID của nó từ đó. Sau đó, tôi phải khớp ID đó với ID tương ứng trong tệp thứ hai (meteo.csv) rồi chỉnh sửa thông tin thời tiết của nó, nằm trong tệp thứ hai. Tuy nhiên, tôi không biết cách lấy ID thành phố từ tệp đầu tiên và cách chỉnh sửa tệp thứ hai sau khi nhận được tất cả thông tin thời tiết mới. Đây là mã:
làm mất hiệu lực addInfo() {
TẬP TIN *fp;
char id_city[100];
thành phố char[100];
độ ẩm than [100];
char temp_max[100];
char temp_min[100];
áp suất than [100];
ngày ký tự [100];
printf("Tên thành phố: ");
scanf("%s", thành phố);
// Tôi nghĩ ở đây tôi phải viết mã để lấy id của thành phố từ tệp đầu tiên
if (id_city != NULL) {
printf("Nhiệt độ tối đa: ");
scanf("%s", temp_max);
printf("Nhiệt độ tối thiểu: ");
scanf("%s", temp_min);
printf("Độ ẩm: ");
scanf("%s", độ ẩm);
printf("Áp suất: ");
scanf("%s", áp suất);
printf("Ngày, ở định dạng YYYY-MM-DD: ");
scanf("%s", ngày);
fp = fopen ("meteo.csv", "a");
fprintf(fp, "%s, %s, %s, %s, %s \n", temp_max, temp_min, độ ẩm, áp suất, ngày tháng); //Tôi nghĩ có gì đó không ổn ở đây...
fclose(fp);
printf("Thông tin đã được chỉnh sửa thành công");
}
Tệp city.csv có 152 hàng và 4 cột:
(id_city,thành phố,quận,quận)
Ví dụ
(56,Lisbon,Lisbon,Lisbon)
Tệp meteo.csv có 152 hàng và 7 cột:
(id_meteo_city,id_city,temp_max,temp_min,độ ẩm,áp suất,ngày)
Ví dụ
(56,56,14,5,62,1025,2018-02-12)
Điều đầu tiên tôi làm là gói gọn dữ liệu vào struct
, điều này giúp việc ánh xạ một hàng của tệp CSV tới một đối tượng đại diện cho một hàng trở nên dễ dàng hơn.
nếu tập tin thành phố.csv
Và sao băng.csv
tất cả đều có các cột khác nhau, tôi sẽ tạo một tệp có các cột khác nhaustruct
. Nếu hai tệp có cùng cột, bạn có thể sử dụngkết cấu
. Tôi giả sử hai tập tin này khác nhau và thành phố
được định dạng meteo_id,city_id,tên
.
typedef cấu trúc thành phố_t {
int meteo_id;
int city_id;
char name[100]; // không có thành phố nào nên có
// dài hơn 100 ký tự
} thành phố_t;
typedef cấu trúc meteo_t {
int meteo_id;
int city_id;
int tempt_max;
int tempt_mix;
độ ẩm gấp đôi;
áp lực gấp đôi;
ngày ký tự [11];
} meteo_t;
Giả sử cả hai file đều đúng định dạng, nếu không bạn sẽ phải viết code kiểm tra lỗi và xử lý chúng, đây sẽ là bước tiếp theo trong bài tập nên tôi sẽ chỉ viết phiên bản cơ bản với các lỗi cơ bản được nhận dạng .
#include
#include
#include
// lấy 2 tham số, tên file và một con trỏ
// tới size_t nơi lưu trữ số lượng thành phố
city_t *read_cities(const char *tên tệp, size_t *len)
{
if(tên tệp == NULL || len == NULL)
trả về NULL;
TẬP TIN *fp = fopen(tên tệp, "r");
nếu(fp == NULL)
{
fprintf(stderr, "Không thể mở %s: %s\n", tên tập tin, strerror(errno));
trả về NULL;
}
city_t *arr = NULL, *tmp;
*len = 0;
// giả sử rằng không có dòng nào dài hơn 1023 ký tự
dòng char[1024];
while(fgets(line, sizeof line, fp))
{
tmp = realloc(arr, (*len + 1) * sizeof *arr);
nếu(tmp == NULL)
{
fprintf(stderr, "không thể phân tích toàn bộ tập tin %s\n", tên tập tin);
// trả về tất cả các thành phố được phân tích cho đến nay
nếu(*len == 0)
{
miễn phí(arr);
mảng = NULL;
}
trả lại mảng;
}
mảng = tmp;
// %99[^\n] là đọc tối đa 99 ký tự cho đến hết dòng
if(sscanf(line, "%d,%d,%99[^\n]", &(arr[*len].meteo_id),
&(arr[*len].city_id), arr[*len].name) != 3)
{
fprintf(stderr, "Định dạng dòng không hợp lệ (bỏ qua dòng):\n%s\n", line);
// bỏ qua dòng này và giảm *len
(*len)--;
continue;
}
// chỉ tăng khi phân tích dòng ổn
(*len)++;
}
fclose(fp);
// tập tin trống hoặc
// tất cả các dòng đều có định dạng sai
nếu(*len == 0)
{
miễn phí(arr);
mảng = NULL;
}
trả lại mảng;
}
void print_cities(city_t *cities, size_t len, FILE *fp)
{
if(thành phố == NULL || fp == NULL)
return;
for(size_t i = 0; i < len; ++i)
fprintf(fp, "%d,%d,%s\n", thành phố[i].meteo_id, thành phố[i].citiy_id,
thành phố[i].name);
}
Bây giờ tôi có tập tin thành phố.csv
Chức năng đọc và ghi bằng văn bản, giả sử định dạng meteo_id;city_id;tên
. print_city
Cho phép bạn in nội dung của màn hình CSV (thay thế thiết bị xuất chuẩn
được chuyển làm đối số cuối cùng) hoặc tệp ( TÀI LIỆU
đối tượng được truyền làm tham số cuối cùng).
Bạn có thể sử dụng các hàm này làm mẫu để đọc và viếtsao băng.csv
, ý tưởng là như nhau.
Bạn có thể sử dụng các tính năng này như sau:
int main(void)
{
size_t thành phố_len;
city_t *cities = read_cities("city.csv", &cities_len);
// lỗi
if(thành phố == NULL)
return 1;
do_something_with_cities(thành phố, thành phố_len);
// cập nhật csv
TỆP *fp = fopen("city.csv", "w");
nếu(fp == NULL)
{
fprintf(stderr, "Không thể mở city.csv để đọc: %s\n",
lỗi strerror(errno));
miễn phí (thành phố);
return 1;
}
print_cities(thành phố, thành phố_len, fp);
fclose(fp);
miễn phí (thành phố);
return 0;
}
Bây giờ là bài tập: viết một hàm tương tự để phân tích cú pháp sao băng.csv
(Không khó lắm khi sử dụng chức năng của tôi làm mẫu) và phân tích cả hai tệp. Bây giờ bạn đã có chúng trong bộ nhớ, thật dễ dàng thao tác với dữ liệu (chèn, cập nhật, xóa). Sau đó viết file như tôi đã làm trong ví dụ và thế là xong.
Mẹo cuối cùng: Cách tìm kiếm thành phố:
// trả về chỉ mục trong mảng hoặc -1 nếu có lỗi hoặc khi không tìm thấy
int search_for_city_by_name(city_t *thành phố, size_t len, const char *name)
{
if(thành phố == NULL || tên == NULL)
return -1;
for(size_t i = 0; i < len; ++i)
if(strcmp(tên, thành phố[i].name) == 0)
trả lại tôi;
// không tìm thấy
return -1;
}
Bây giờ tôi đã giao cho bạn hầu hết các phần của bài tập, tất cả những gì bạn phải làm là dán chúng lại với nhau và tạo ra sao băng.csv
tập tin ghi chức năng tương tự.
Tôi là một lập trình viên xuất sắc, rất giỏi!