Coding/C

[C언어] 파일에서 문자열 읽고 쓰기 - 코딩도장

GunP4ng 2024. 2. 29. 23:36

[코딩도장] Unit 70


1. 파일에 문자열 읽고 쓰기 (fprintf, fscanf)

1. 파일 포인터 사용하기 (fopen)

C언어에서 파일을 사용하기 위해서는 fopen 함수로 파일을 열고

파일 포인터를 얻어야 한다

//    ↓ 파일 포인터
FILE *fp = fopen("hello.txt", "w");           // hello.txt 파일을 쓰기 모드(w)로 열기. 
//                   ↑          ↖ 파일 모드   // 파일 포인터를 반환
//        파일 이름 또는 파일 경로

FILE 구조체는 stdio.h 헤더파일에 정의되어 있다

보통 FILE 과 * 를 합쳐서 파일 포인터라 부른다

 

파일 모드의 종류는

  • r     읽기 전용  -  파일을 읽기 전용으로 연다 (반드시 파일이 있어야 함)
  • w    쓰기 전용  -  새 파일 생성 (파일이 있다면 내용을 덮어씀)
  • a     추가          -   파일 끝에 값을 이어 씀 (파일이 없다면 파일 생성)
  • r+    읽기/쓰기  -   파일을 읽기/쓰기용으로 연다 (파일이 없다면 NULL 반환)
  • w+   읽기/쓰기  -   파일을 읽기/쓰기으로 연다 (파일이 없다면 파일 생성, 있으면 덮어씀)
  • a+    추가(읽기/쓰기)  -  파일 끝에 값을 이어 씀 (읽기는 모든 구간 가능, 쓰기는 파일 끝에서만 가능)
  • t       텍스트 모드        -  파일을 읽고 쓸 때 개행문자 \n와 \r\n을 서로 변환
  • b      바이너리 모드    -  파일의 내용을 그대로 읽고, 값을 그대로 씀

t 와 b 는 단독으로 사용할 수 없다

 

2. 서식을 지정하여 파일에 문자열 쓰기 (fprintf)

fprintf 함수로 문자열을 파일에 쓸 수 있다

파일 포인터를 지정하고 서식과 값을 순서대로 지정하면 된다

fprintf(fp, "%s %d\n", "Hello", 100);   // 서식을 지정하여 문자열을 파일에 저장

 

함수가 끝났으면 반드시 fclose 함수로 파일 포인터를 닫아준다

fclose(fp);    // 파일 포인터 닫기

fclose 함수로 닫아주지 않으면 메모리 누수가 발생한다 

 

fprintf 함수로도 화면에 문자열을 출력할 수 있다

fprintf(stdout, "%s %d\n", "Hello", 100);   // Hello 100: 서식을 지정하여 화면(stdout)에 문자열 출력

stdout 매크로를 활용하면 된다

 

3. 서식을 지정하여 파일에서 문자열 읽기 (fscanf)

fscanf 함수로 서식을 지정하여 파일의 내용을 읽을 수 있다

stduio.h 헤더 파일에 선언되어 있다

fscanf(fp, "%s %d", s1, &num1);    // 서식을 지정하여 파일에서 문자열 읽기

fscanf 함수는 파일 포인터를 넣는다는 점 말고는 scanf 와 사용법이 같다

파일에서 문자열을 읽은 뒤 서식에 맞추어서 값을 변수에 저장한다

 

파일 작업이 끝났다면 fclose 함수로 파일 포인터를 닫아준다

fclose(fp);   // 파일 포인터 닫기

 

fscanf 함수로도 stdin 매크로를 활용하면 사용자가 입력한 값을

변수에 저장할 수 있다

fscanf(stdin, "%s %d", s1, &num1);    // 서식을 지정하여 표준 입력(stdin)에서 문자열 읽기

 

 

2. 파일에 문자열 쓰기 (fputs, fwrite)

1. fputs 함수 사용하기

fputs 함수를 사용하면 서식 없이 문자열을 그대로 쓸 수 있다

stdio.h 헤더 파일에 선언되어 있다

  • fputs(버퍼, 파일포인터)
fputs("Hello, world!", fp);    // 파일에 문자열 저장

fputs 는 파일에 쓸 문자열(배열이나, 포인터)과 파일 포인터 fp를 넣어주면 된다

 

fputs 함수도 파일 포인터 대신 stdout 을 지정하면

문자열이 표준 출력(화면)에 출력된다

fputs("Hello, world!", stdout);    // Hello, world!: 표준 출력(stdout)에 문자열 출력

 

 

2. fwrite 함수 사용하기

fwrite 함수를 사용하여 문자열을 파일에 쓸 수도 있다

stdio.h 헤더 파일에 선언되어 있다

  • fwrite(버퍼, 쓰기크기, 쓰기횟수, 파일포인터)
fwrite(s1, strlen(s1), 1, fp);    // strlen으로 문자열의 길이를 구함.
                                  // 문자열의 길이만큼 1번 파일에 저장

fwrite 함수는 fputs 함수와 달리 쓰기 횟수를 지정해야 한다

쓰기 크기에는 strlen(s1) 과 같이 문자열의 길이를 구해서 넣는다

쓰기 횟수에는 1을 넣고 파일 포인터 fp 를 넣어주면 된다

 

※ fwrite 함수에서 파일을 쓰는 크기는 (쓰기 크기 * 쓰기 횟수)이다

 

fwrite 함수도 파일 포인터 대신 stdout을 지정하면

문자열이 화면에 출력된다

fwrite(s1, strlen(s1), 1, stdout);    // Hello, world!
                                      // 문자열 길이만큼 표준출력(stdout)에 문자열 출력

 

 

3. 파일에서 문자열 읽기 (fgets, fread)

1. fgets 함수 사용하기

파일을 읽을 때는 fgets 함수로 파일의 내용을 읽는다

stdio.h 헤더 파일에 선언되어 있다

  • fgets(버퍼, 버퍼크기, 파일포인터)

파일을 읽을 때 사용할 임시 공간(버퍼)를 선언한다

char buffer[20];    // 파일을 읽을 때 사용할 임시 공간

fgets(buffer, sizeof(buffer), fp);     // hello.txt에서 문자열을 읽음

버퍼에는 앞에서 선언한 buffer 를 넣고

버퍼 크기에는 sizeof(buffer) 와 같이 버퍼의 크기를 구해서 넣는다

마지막에는 파일 포인터를 넣는다

 

fgets 함수는 딱 버퍼 크기만큼만 읽는다

버퍼 크기를 20바이트로 지정한다면 널 문자를 포함하여 20바이트를 읽고

실제 문자열은 19바이트가 된다

 

※ 읽는 문자열에 줄바꿈(\n)이 있으면 버퍼 크기와는 상관없이 \n 까지 문자열을 읽는다

(\n 도 포함해서 읽는다)

 

fgets(buffer, sizeof(buffer), stdin);    // 표준 입력(stdin)에서 20바이트만큼 문자열 읽기

fgets 함수도 stdin 을 지정하면 사용자가 입력한 문자열을 버퍼에 저장한다

지정한 버퍼크기보다 작은 상태에서

엔터(\n)를 누르면 엔터(\n)까지 입력받는다

 

2. fread 함수 사용하기

fread 함수도 문자열을 읽을 수 있다

stdio.h 헤더 파일에 선언되어 있다

  • fread(버퍼, 읽기크기, 읽기횟수, 파일포인터)

fread 함수를 사용할 때는 char 배열을 선언한 뒤 반드시 0으로 초기화해야 한다

char buffer[20] = { 0, };    // 파일을 읽을 때 사용할 임시 공간, 미리 0으로 전부 초기화

fread(buffer, sizeof(buffer), 1, fp);   // hello.txt에서 버퍼 크기(20바이트)만큼 1번 값을 읽음

 

 

앞에서 선언한 buffer 를 넣어준다

읽기 크기에는 sizeof(buffer)와 같이 버퍼의 크기를 넣고

읽기 횟수에는 1을 지정하여 버퍼 크기만큼 읽는다

마지막에는 파일 포인터 fp를 넣어준다

 

fread 함수에서 파일을 읽는 크기는 (읽기 크기 * 읽기 횟수)이다

fread 함수는 fgets 함수와는 달리 \n 이 있든 없든 지정된 크기만큼 읽는다

 

버퍼를 0으로 초기화하지 않고 fread로 파일을 읽으면

문자열 이외에 쓸데없는 값들이 출력된다

buffer 초기화 여부에 따른 차이

 

fread 함수도 stdin 을 지정하면 사용자가 입력한 문자열을 버퍼에 저장한다

fread 함수는 무조건 지정된 크기만큼 읽으므로

버퍼 끝에 NULL이 들어갈 수 있도록 읽기 크기는 버퍼 크기보다 1이 작도록 만든다

char buffer[20] = { 0, };
fread(buffer, sizeof(buffer) - 1, 1, stdin);    // 표준 입력(stdin)에서 문자열 읽기
                     // 버퍼 끝에 NULL이 들어갈 수 있도록 sizeof(buffer) - 1을 지정

 

 

4. 심사문제

70.8 서식을 지정하여 파일에 문자열 쓰기

표준 입력으로 길이 30이하의 문자열과 정수가 입력됩니다. 다음 소스 코드를 완성하여 입력된 문자열과 숫자를 조합만 문자열을 stdout 에 쓰도록 만드세요.

정답에는 밑줄 친 부분에 들어갈 코드만 작성해야 합니다

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
    char name[31];
    int order;

    scanf("%s %d", name, &order);

    FILE *fp = stdout;

    fprintf(_________________________________________);

    fclose(fp);

    return 0;
}

 

정답

stdout, "The %dth Satellite of Jupiter: %s", order, name

 

70.9 파일에서 문자열 읽기

최대 길이 100자 미만의 문자열이 저장된 words.txt 파일이 주어집니다. 다음 소스 코드를 완성하여 words.txt 에서 문자열을 읽도록 만드세요.

정답에는 밑줄 친 부분에 들어갈 코드만 작성해야 합니다.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    char *buffer = malloc(100);
    memset(buffer, 0, 100);

    FILE *fp = fopen("words.txt", "r");

    ___________________

    printf("%s\n", buffer);

    fclose(fp);

    free(buffer);

    return 0;
}

 

정답

fgets(buffer, 100, fp);