도입 문구
C언어에서 CSV 파일을 읽고 쓰는 방법은 많은 프로그래밍 프로젝트에서 중요한 기술입니다. 본 기사에서는 C언어를 사용하여 CSV 파일을 처리하는 방법을 단계별로 설명합니다. CSV 파일은 데이터를 저장하고 공유하는 데 많이 사용되며, 이를 효율적으로 다루는 능력은 소프트웨어 개발에서 유용하게 활용될 수 있습니다.
C언어에서 파일 입출력 이해하기
C언어에서 파일을 다루는 기본적인 방법은 파일을 여는 것부터 시작합니다. 파일 입출력 함수는 주로 fopen()
, fclose()
, fread()
, fwrite()
, fscanf()
, fprintf()
등을 사용합니다.
파일 열기
파일을 열기 위해서는 fopen()
함수를 사용합니다. 이 함수는 파일의 경로와 열기 모드를 인수로 받아 파일 포인터를 반환합니다. 열기 모드는 읽기, 쓰기, 추가 등의 옵션이 있습니다. 예를 들어, 파일을 읽기 모드로 열 때는 "r"
모드를 사용합니다.
FILE *file = fopen("data.csv", "r");
파일 닫기
파일 작업이 끝난 후에는 반드시 fclose()
함수를 사용하여 파일을 닫아야 합니다. 이 함수는 파일 포인터를 인수로 받아 파일을 안전하게 닫습니다.
fclose(file);
파일 포인터
파일 포인터는 파일에 접근하는 중요한 요소로, 파일의 내용을 읽거나 쓸 때 사용됩니다. 파일을 열고 나면, 이 포인터를 사용하여 데이터에 접근할 수 있습니다.
CSV 파일 포맷 소개
CSV(Comma-Separated Values) 파일 포맷은 데이터를 쉼표로 구분하여 저장하는 형식입니다. 각 행은 데이터의 한 레코드를 나타내며, 각 필드는 쉼표로 구분됩니다. CSV 파일은 텍스트 형식으로 저장되어, 다양한 프로그램에서 쉽게 읽고 쓸 수 있는 장점이 있습니다.
CSV 파일의 구조
CSV 파일은 기본적으로 한 줄씩 데이터를 저장합니다. 각 줄은 개별 데이터 항목들이 쉼표로 구분되어 있으며, 일반적으로 각 필드는 텍스트 형식으로 저장됩니다. 예를 들어, 다음은 간단한 CSV 파일의 내용입니다.
이름,나이,직업
홍길동,30,개발자
김영희,25,디자이너
박철수,40,매니저
CSV 파일의 특징
- 간단한 텍스트 형식: CSV 파일은 특별한 포맷 없이 텍스트로 저장되므로 다른 프로그램과의 호환성이 높습니다.
- 쉬운 파싱: 각 행과 필드를 구분하는 규칙이 명확하여 파싱하기 쉽습니다.
- 확장성: 필요에 따라 더 많은 컬럼을 추가하거나 데이터를 쉽게 수정할 수 있습니다.
이러한 이유로 CSV 파일은 많은 애플리케이션에서 데이터를 저장하고 교환하는 데 널리 사용됩니다.
CSV 파일 읽기 기본 예제
C언어로 CSV 파일을 읽는 기본적인 방법은 fopen()
함수를 사용하여 파일을 열고, fgets()
함수로 파일에서 한 줄씩 데이터를 읽어오는 것입니다. 이후 읽어온 데이터를 처리하기 위해 strtok()
함수를 사용하여 각 필드를 구분할 수 있습니다.
CSV 파일 읽기 예제 코드
다음은 간단한 CSV 파일을 읽고, 각 행의 데이터를 출력하는 예제 코드입니다.
#include <stdio.h>
#include <string.h>
int main() {
FILE *file = fopen("data.csv", "r"); // 파일 열기
char line[256]; // 한 줄을 저장할 배열
if (file == NULL) {
printf("파일을 열 수 없습니다.\n");
return 1;
}
// 파일에서 한 줄씩 읽기
while (fgets(line, sizeof(line), file)) {
// 한 줄을 읽고 출력
printf("%s", line);
}
fclose(file); // 파일 닫기
return 0;
}
동작 설명
fopen()
함수로data.csv
파일을 읽기 모드("r"
)로 엽니다.fgets()
함수는 파일에서 한 줄씩 읽어서line
배열에 저장합니다.- 파일 끝까지 읽은 후에는
fclose()
함수로 파일을 닫습니다. - 이 코드에서는 각 줄을 읽고 그대로 출력하는 간단한 예제를 보여줍니다.
파일에서 한 줄씩 읽기
CSV 파일을 읽을 때는 데이터를 한 줄씩 처리하는 것이 중요합니다. C언어에서는 fgets()
함수를 사용하여 파일에서 한 줄을 읽을 수 있습니다. 읽은 후, 해당 줄의 데이터를 분리하여 각 필드를 추출하는 작업을 해야 합니다. 이때 strtok()
함수를 사용하면 쉼표를 기준으로 각 필드를 쉽게 구분할 수 있습니다.
한 줄씩 읽고 필드 구분하기
다음은 CSV 파일에서 한 줄씩 읽고, 각 필드를 분리하여 출력하는 예제입니다.
#include <stdio.h>
#include <string.h>
int main() {
FILE *file = fopen("data.csv", "r"); // 파일 열기
char line[256]; // 한 줄을 저장할 배열
if (file == NULL) {
printf("파일을 열 수 없습니다.\n");
return 1;
}
// 파일에서 한 줄씩 읽기
while (fgets(line, sizeof(line), file)) {
// 각 줄에서 쉼표로 구분된 필드 추출
char *token = strtok(line, ",");
while (token != NULL) {
printf("%s\t", token); // 각 필드를 출력
token = strtok(NULL, ","); // 다음 필드로 이동
}
printf("\n"); // 한 줄 출력 후 줄 바꿈
}
fclose(file); // 파일 닫기
return 0;
}
동작 설명
fgets()
함수를 사용해 파일에서 한 줄을 읽습니다.strtok()
함수는 해당 줄을 쉼표(,) 기준으로 분리하여 각 필드를 추출합니다.while
루프를 사용하여 각 필드를 추출하고 출력합니다.- 필드를 출력한 후에는
strtok()
을 계속 호출하여 다음 필드를 가져옵니다. - 각 필드를 출력한 뒤, 줄 바꿈을 추가하여 데이터를 한 줄씩 출력하도록 합니다.
이 방식으로 CSV 파일의 각 줄을 읽고 데이터를 분리하여 활용할 수 있습니다.
CSV 데이터 파싱하기
CSV 파일에서 각 필드를 추출한 후에는 데이터를 파싱하여 적절하게 활용하는 과정이 필요합니다. C언어에서는 strtok()
함수를 사용하여 쉼표로 구분된 데이터를 각 필드로 나누지만, 때로는 숫자나 날짜 형식처럼 더 복잡한 데이터 타입을 처리해야 할 수 있습니다. 이때는 문자열을 적절한 형식으로 변환하여 사용해야 합니다.
숫자 데이터 파싱하기
CSV 파일에서 읽은 데이터가 숫자인 경우, atoi()
나 atof()
함수를 사용하여 문자열을 정수나 실수로 변환할 수 있습니다. 예를 들어, “25”라는 문자열을 정수 25로 변환할 때 atoi()
함수를 사용합니다.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
FILE *file = fopen("data.csv", "r"); // 파일 열기
char line[256]; // 한 줄을 저장할 배열
if (file == NULL) {
printf("파일을 열 수 없습니다.\n");
return 1;
}
// 파일에서 한 줄씩 읽기
while (fgets(line, sizeof(line), file)) {
// 각 줄에서 쉼표로 구분된 필드 추출
char *token = strtok(line, ",");
int fieldCount = 0;
while (token != NULL) {
if (fieldCount == 1) { // 두 번째 필드가 숫자라고 가정
int age = atoi(token); // 문자열을 정수로 변환
printf("나이: %d\n", age);
} else {
printf("%s\t", token); // 다른 필드는 그대로 출력
}
token = strtok(NULL, ","); // 다음 필드로 이동
fieldCount++;
}
printf("\n"); // 한 줄 출력 후 줄 바꿈
}
fclose(file); // 파일 닫기
return 0;
}
실수 데이터 파싱하기
실수 데이터를 처리할 때는 atof()
함수를 사용하여 문자열을 실수로 변환합니다. 예를 들어, “25.75”라는 문자열을 실수 25.75로 변환할 수 있습니다.
float height = atof(token); // 문자열을 실수로 변환
데이터 파싱 후 활용
CSV 파일을 읽고 데이터를 파싱한 후에는 프로그램의 요구에 맞게 데이터를 활용할 수 있습니다. 예를 들어, 숫자 데이터를 계산하거나 필드를 이용해 특정 작업을 수행하는 등의 처리가 가능합니다. 파싱된 데이터를 구조체나 배열에 저장하여 후속 작업에 활용할 수도 있습니다.
이와 같은 데이터 파싱 기법을 활용하면 다양한 형식의 데이터를 효율적으로 처리할 수 있습니다.
CSV 파일 쓰기 기본 예제
C언어에서 CSV 파일에 데이터를 쓰는 방법은 fopen()
함수로 파일을 열고, fprintf()
함수를 사용하여 데이터를 형식에 맞게 출력하는 방식입니다. 데이터를 파일에 쓸 때는 각 필드를 쉼표로 구분하여 한 줄씩 기록합니다.
CSV 파일 쓰기 예제 코드
다음은 C언어로 데이터를 CSV 파일에 쓰는 기본적인 예제입니다.
#include <stdio.h>
int main() {
FILE *file = fopen("output.csv", "w"); // 파일 열기 (쓰기 모드)
if (file == NULL) {
printf("파일을 열 수 없습니다.\n");
return 1;
}
// 헤더 정보 작성
fprintf(file, "이름,나이,직업\n");
// 데이터 작성
fprintf(file, "홍길동,30,개발자\n");
fprintf(file, "김영희,25,디자이너\n");
fprintf(file, "박철수,40,매니저\n");
fclose(file); // 파일 닫기
return 0;
}
동작 설명
fopen()
함수로output.csv
파일을 쓰기 모드("w"
)로 엽니다. 파일이 없으면 새로 생성되고, 기존에 있으면 덮어씁니다.fprintf()
함수는 파일에 데이터를 형식에 맞게 기록합니다. 첫 번째 인수로 파일 포인터를, 두 번째 인수로 출력할 문자열을 전달합니다.- 파일의 첫 번째 줄에 헤더를 작성하고, 그 이후에 각 데이터 항목을 쉼표로 구분하여 파일에 작성합니다.
fclose()
함수로 파일을 안전하게 닫습니다.
이 방법을 통해 C언어에서 간단하게 CSV 파일에 데이터를 작성할 수 있습니다.
CSV 파일의 데이터 처리 예시
CSV 파일에 여러 행과 열의 데이터를 처리하는 경우, 각 필드를 읽고 적절히 처리하는 과정이 필요합니다. C언어에서는 파일을 한 줄씩 읽고, 각 필드를 분리한 후, 데이터를 배열이나 구조체에 저장하여 처리할 수 있습니다. 아래 예제는 여러 행의 데이터를 읽고, 배열을 사용하여 데이터를 처리하는 방법을 보여줍니다.
여러 행의 데이터 처리 예제
다음은 CSV 파일에서 여러 행과 열을 읽고, 그 데이터를 배열에 저장하여 처리하는 예제 코드입니다. 이 코드에서는 fgets()
와 strtok()
을 사용하여 CSV 데이터를 읽고 각 필드를 처리합니다.
#include <stdio.h>
#include <string.h>
#define MAX_ROWS 100
#define MAX_COLS 3
int main() {
FILE *file = fopen("data.csv", "r"); // 파일 열기
char line[256]; // 한 줄을 저장할 배열
char data[MAX_ROWS][MAX_COLS][50]; // 데이터 저장 배열 (최대 100행, 3열)
if (file == NULL) {
printf("파일을 열 수 없습니다.\n");
return 1;
}
int row = 0;
// 파일에서 한 줄씩 읽기
while (fgets(line, sizeof(line), file)) {
char *token = strtok(line, ",");
int col = 0;
// 각 줄에서 쉼표로 구분된 필드 추출
while (token != NULL) {
strncpy(data[row][col], token, sizeof(data[row][col]) - 1); // 데이터 저장
token = strtok(NULL, ","); // 다음 필드로 이동
col++;
}
row++;
}
fclose(file); // 파일 닫기
// 저장된 데이터를 출력
for (int i = 0; i < row; i++) {
for (int j = 0; j < MAX_COLS; j++) {
printf("%s\t", data[i][j]); // 저장된 데이터 출력
}
printf("\n");
}
return 0;
}
동작 설명
fgets()
함수를 사용하여 파일에서 한 줄씩 읽습니다.strtok()
함수로 쉼표를 기준으로 각 필드를 분리하여data
배열에 저장합니다.data
배열은 최대 100개의 행과 3개의 열을 저장할 수 있으며, 각 필드는 50자까지 저장할 수 있습니다.- 데이터가 저장된 후, 이 데이터를 출력하여 확인합니다.
이 방식은 CSV 파일에서 여러 행과 열을 효율적으로 읽고, 배열이나 다른 데이터 구조에 저장하여 추가적인 작업을 수행할 수 있게 해줍니다.
오류 처리 및 예외 처리
파일 입출력 과정에서 오류가 발생할 수 있습니다. C언어에서는 파일을 열거나 데이터를 읽고 쓸 때 다양한 오류가 발생할 수 있기 때문에 이를 적절히 처리하는 것이 중요합니다. 오류 처리를 통해 프로그램이 예기치 않게 종료되거나 잘못된 데이터를 처리하는 상황을 예방할 수 있습니다.
파일 열기 오류 처리
파일을 열 때 fopen()
함수가 실패하면 NULL 포인터를 반환합니다. 따라서 파일이 제대로 열렸는지 확인하고, 열리지 않으면 적절한 오류 메시지를 출력하는 것이 좋습니다.
FILE *file = fopen("data.csv", "r"); // 파일 열기
if (file == NULL) {
printf("파일을 열 수 없습니다.\n");
return 1; // 오류가 발생한 경우 프로그램 종료
}
파일 읽기 오류 처리
파일을 읽을 때는 fgets()
나 fscanf()
등의 함수가 성공적으로 데이터를 읽었는지 확인하는 것이 중요합니다. 읽기 실패 시, 파일의 끝에 도달했거나 다른 오류가 발생한 것일 수 있습니다. 파일 끝을 확인하는 방법은 feof()
함수로 할 수 있으며, ferror()
함수로 파일 입출력 오류를 확인할 수 있습니다.
if (fgets(line, sizeof(line), file) == NULL) {
if (feof(file)) {
printf("파일 끝에 도달했습니다.\n");
} else if (ferror(file)) {
printf("파일 읽기 오류가 발생했습니다.\n");
}
}
파일 쓰기 오류 처리
파일에 데이터를 쓸 때는 fprintf()
와 같은 함수를 사용하여 데이터를 기록합니다. 데이터를 쓸 때도 오류가 발생할 수 있으므로, 파일에 정상적으로 기록되었는지 확인하는 것이 좋습니다. fprintf()
함수는 출력된 문자 수를 반환하므로, 반환값을 체크하여 오류를 감지할 수 있습니다.
if (fprintf(file, "데이터\n") < 0) {
printf("파일 쓰기 오류가 발생했습니다.\n");
fclose(file); // 오류 발생 시 파일 닫기
return 1;
}
파일 닫기 오류 처리
파일을 닫을 때는 fclose()
함수를 사용하지만, 이 함수가 실패할 수도 있습니다. 파일을 닫는 데 문제가 있으면, fclose()
함수는 비-제로 값을 반환합니다. 파일을 제대로 닫지 않으면 리소스 누수나 데이터 손상 등의 문제가 발생할 수 있으므로, 이 반환값도 확인하는 것이 좋습니다.
if (fclose(file) != 0) {
printf("파일을 닫는 데 오류가 발생했습니다.\n");
return 1;
}
종합적인 오류 처리 예제
다음은 파일을 읽고 데이터를 처리하는 동안 발생할 수 있는 여러 오류를 처리하는 예제입니다.
#include <stdio.h>
#include <string.h>
int main() {
FILE *file = fopen("data.csv", "r"); // 파일 열기
if (file == NULL) {
printf("파일을 열 수 없습니다.\n");
return 1; // 오류 발생 시 프로그램 종료
}
char line[256];
while (fgets(line, sizeof(line), file)) {
if (ferror(file)) {
printf("파일 읽기 오류가 발생했습니다.\n");
fclose(file);
return 1;
}
printf("%s", line);
}
if (fclose(file) != 0) {
printf("파일을 닫는 데 오류가 발생했습니다.\n");
return 1;
}
return 0;
}
요약
파일 입출력 과정에서 발생할 수 있는 오류를 적절히 처리하는 것은 프로그램의 안정성과 신뢰성을 높이는 중요한 작업입니다. 파일 열기, 읽기, 쓰기, 닫기 과정에서 발생할 수 있는 오류를 확인하고, 오류가 발생한 경우 적절한 메시지를 출력하거나 예외 처리를 하여 프로그램이 예기치 않게 종료되지 않도록 해야 합니다.
요약
본 기사에서는 C언어에서 CSV 파일을 읽고 쓰는 방법에 대해 다루었습니다. 파일 입출력의 기본 개념과 fopen()
, fgets()
, fprintf()
등의 함수를 사용한 예제 코드를 통해, CSV 파일의 처리 과정—데이터 읽기, 파싱, 쓰기—을 자세히 설명했습니다. 또한, 데이터를 한 줄씩 읽고 필드를 분리하는 방법, 오류 처리 및 예외 처리를 통해 파일 작업 중 발생할 수 있는 문제를 예방하고 안정성을 높이는 방법을 소개했습니다.
CSV 파일을 처리하는 기본적인 기술을 이해하고 활용함으로써, 다양한 데이터 작업을 효율적으로 처리할 수 있습니다.