본문 바로가기
c언어

c언어 파일의 기초에 대하여 알아보기

by 개발자 L 2023. 2. 15.
반응형

c언어 파일의 기초에 대하여 알아보기

네 안녕하세요, 이번 포스팅에서는 파일의 기초에 대하여 알아보려 합니다.

사실 프로그래밍의 꽃은 크게 두 가지입니다.

첫 번째는 데이터베이스이고,

두 번째가 파일 처리입니다.

그리고 개발자는 파일 처리를 여러 가지 프로그래밍 언어로 처리를 하기 때문에

프로그래밍 언어에 대하여 공부하고 적용하는 것입니다.

그래서 이번 포스팅에서는 이러한 파일 처리에 대한 기본적인 부분들에 대하여 알아보도록 하겠습니다.

 

1. 파일의 개념

c언어에서의 입출력은 스트림을 통해 이루어지고,

파일 또한 예외가 아닙니다.

그 이유는 파일 역시 용량이 바이트 단위이기 때문에

컴퓨터는 파일을 '연속된 바이트'라고 여깁니다.

그래서 파일의 입출력 역시 우리가 평소에 소스를 작성했던 것과 같이 똑같이 작업이 이루어집니다.

그리고 이러한 입출력을 하기 위해서 개발자는 파일의 이름을 직접 결정하여 파일 스트림을 생성합니다.

그리고 모든 파일은 입출력 동작이 발생하는 위치가 해당 파일의 주소가 됩니다.

그리고 이를 '파일 포인터'라고 부릅니다.

그래서 파일 포인터는 파일의 제일 첫 번째 바이트를 가리키며,

입출력이 진행이 되면 파일 포인터가 자동으로 이동하게 됩니다.

 

2. 파일의 유형

파일의 유형은 크게 두 가지입니다.

  • 텍스트 파일(text file)
  • 이진 파일(binary file)

 

2 - 1. 텍스트 파일

텍스트 파일은 사람이 읽을 수 있는 텍스트가 들어있는 파일입니다.

소스 파일이나 메모장 파일 역시 사람이 읽을 수 있기 때문에 텍스트 파일의 범주에 들어갑니다.

이러한 텍스트는 아스키코드로 표현이 되며,

이 텍스트가 중요한 이유는 컴퓨터 주변 기기인 모니터, 프린터, 키보드 등은 모두 문자 데이터만 처리하기 때문에

텍스트가 매우 중요한 역할을 합니다.

그리고 텍스트는 여러 개의 줄(line)로 되어있는데,

이 줄은 줄의 끝을 알리는 문자로 항상 끝이 납니다.

그리고 이러한 문자는 두 가지가 있습니다.

  • 줄 바꿈 문자('\n\)
  • 캐리지 리턴(줄의 맨 앞으로 이동하라는 뜻) 문자('\r')

이 중에서 윈도에서는 줄 바꿈 문자와 캐리지 리턴 문자 두 개를 모두 써서 줄의 끝을 알림과 동시에 개행을 하고,

유닉스나 리눅스 체제의 경우는 줄바꿈 문자만을 사용하여 개행을 하고,

매킨토시(ios)의 경우에는 캐리지 리턴 문자만을 사용해서 개행을 합니다.

 

2 - 2. 이진 파일

이진 파일은 컴퓨터가 읽을 수 있는 파일을 이야기합니다.

그렇기 때문에 문자 데이터가 아니라 이진 데이터가 저장이 되어있습니다.

그리고 2진수로 이루어진 이진 데이터는 줄이라는 개념이 없어서 줄의 끝을 표시할 필요가 없고,

NULL 문자나 개행 문자, 캐리지 리턴 문자 등도 그냥 일반 데이터로 취급이 됩니다.

그리고 이러한 파일의 예시로는 이러한 것들이 있습니다.

  • 실행 파일
  • 사운드 파일
  • 이미지 파일
반응형

 

3. 파일 처리의 개요

파일 처리의 기능은 크게 3가지입니다.

  • 파일 열기
  • 파일 닫기
  • 파일 삭제

 

이러한 것들이 있습니다.

여기서 파일 읽기와 쓰기는 파일 열기가 일단 되어야 한다는 전제가 깔리기 때문에 넣지 않았습니다.

 

3 - 1. 파일 열기

파일 열기는 이런 식으로 씁니다.

FILE *fp;
fp = fopen("test.txt", "w");

이런 식으로 씁니다.

여기서 'test.txt'는 파일명이고,

'w'는 파일 모드입니다.

파일을 여는 원리는 fopen() 함수를 써서 파일을 생성하고,

이전에 입력했던 '*fp'라는 파일 포인터를 반환하는 방법으로 실행이 되며,

파일 포인터는 보통 typedef를 이용하여 자료형을 새롭게 정의해서 씁니다.

여기서 FILE은 구조체이며,

이 파일을 연 후에 하는 모든 동작에서 구조체가 필요하기 때문에 구조체를 선언해야 합니다.

그리고 fopen() 함수가 실패하는 경우가 있는데,

제일 대표적인 경우는 잘못된 파일 이름을 가지고서 파일을 열고자 할 때입니다.

그리고 그럴 경우에는 NULL 포인터가 반환이 됩니다.

아래는 파일의 모드를 표로 정리를 해 둔 것입니다.

모드 설명
r 읽기 모드, 파일 부재 시 에러
w 쓰기 모드, 파일이 이미 존재한다면 기존 내용 삭제
a 추가 모드, 파일이 이미 존재한다면 데이터가 파일의 긑에 추가되며, 없다면 새 파일 생성
r+ 읽기 모드로 파일을 열지만 쓰기 모드로 전환 가능, 파일이 반드시 존재해야 함
w+ 쓰기 모드로 새로운 파일을 생성하지만, 읽기 모드로 전환 가능하며, 파일이 이미 존재한다면 기존 내용 삭제
a+ 추가 모드롤 파일을 열지만 읽기 모드로 전환 가능, 데이터 추가 시 EOF 마커를 추가한 데이터의 뒤로 이동하며,
파일 부재 시 새로운 파일 생성
t 텍스트 파일 모드
b 이진 파일 모드

이렇습니다.

그리고 여기서 +가 붙은 모드들이 있을 건데, 이들은 '수정 모드'라고 부릅니다.

각각은 제일 처음 모드는 해당 알파벳이 가지는 모드를 따라갑니다.

그렇지만 필요에 따라서 파일 모드를 변환할 수 있습니다.

하지만 파일의 모드를 변환하려면 특별한 함수를 써야 하는데,

fflush(), fsetpos(), fseek(), rewind() 중에 하나를 호출해서 모드를 변경합니다.

그렇지 않으면 모드 변경은 불가합니다.

 

3 - 2. 파일 닫기

파일 닫기는 이런 식으로 씁니다.

fclose(fp);

파일 포인터를 불러서 닫으며,

성공 시에는 0이 반환되며,

실패 시에는 -1이 반환됩니다.

제가 지금까지 배운 것들을 이용해서 파일 처리의 기본 코드를 보여드리도록 하겠습니다.

#include <stdio.h>

int main()
{
    FILE *fp = NULL;

    fp = fopen("sample.txt", "w");

    if(fp == NULL)
    {
        printf("파일 열기 실패\n");
    }

    else
    {
        printf("파일 열기 성공\n");
    }

    fclose(fp); // fopen()을 호출했다면 반드시 fclose()로 닫아줘야 함.

    return 0;
}

이렇게 작성을 했습니다.

여기서 중요한 점 하나는,

파일을 열었으면 파일을 닫아줘야 한다는 것입니다.

그래서 열기 함수와 닫기 함수는 세트입니다.

그럼 결과를 보도록 하겠습니다.

파일 열기 성공

출력은 이런 식으로 되었습니다.

그리고 제 디렉터리의 함수 호출 전과 후를 보여드리도록 하겠습니다.

이게 파일 처리 소스를 실행하기 전입니다.

그리고 바로 파일 처리 함수 실행 후 사진을 보여드리도록 하겠습니다.

여기 보시면 'sample.txt'라는 파일이 생겨난 것을 확인하실 수 있습니다.

 

3 - 3. 파일 삭제

파일 삭제를 할 때도 라이브러리 함수를 사용합니다.

삭제 함수는 remove()이며,

이를 사용했을 때 성공했으면 0을 반환하고,

실패했다면 -1을 반환합니다.

제가 직접 보여드리도록 하겠습니다.

#include <stdio.h>

int main()
{

    if(remove("sample.txt") == -1)
    {
        printf("sample.txt 파일을 삭제할 수 없습니다.\n");
    }

    else
    {
        printf("sample.txt 파일을 삭제하였습니다.\n");
    }

    return 0;
}

이렇게 작성을 해봤습니다.

결과도 바로 확인해 보도록 하겠습니다.

sample.txt 파일을 삭제하였습니다.

삭제가 잘 되었다고 하는데,

그럼 디렉터리 내에 파일이 완전히 삭제되었는지 보도록 하겠습니다.

보시면 깨끗하게 삭제가 된 것을 확인할 수 있습니다.

 

4. 기타 유용한 함수들

그 외에 파일 처리 시에 사용하는 여러 가지 함수들이 있는데,

제가 아래 표에 정리를 해뒀습니다.

함수 설명
int foef(FILE *stream) 파일의 끝이 도달되면 true 반환
int rename(const char *oldname, const char *newname) 파일 이름 변경
FILE *tmpfile() 임시 파일을 생성하여 반환
int ferror(FILE *stream) 스트림의 오류 상태 반환, 오류 발생 시 true 반환

 

여기까지 파일의 기초에 대하여 알아보았는데요,

다음 포스팅에서는 텍스트 파일 읽기와 쓰기에 대하여 알아보도록 하겠습니다.

긴 글 읽어주신 독자분들께 진심으로 감사드립니다~

반응형

댓글