C 관련 포스팅 목록
2021.12.05 - [C/stdio] - C 파일 실시간 쓰기 예제(stdio/fflush)
2021.12.01 - [C/stdio] - C 파일 생성 및 스트림 열기 예제(stdio/fopen)
2021.11.30 - [C/stdio] - C 파일 스트림 닫기(stdio/fclose)
2020.07.03 - [C/stdio] - C/C++ printf 포맷 API 사용 예제(출력) - 1
2020.07.05 - [C] - C/C++ Hex 문자열 바이트 변환 예제
fseek를 통해 파일 오프셋 이동시키기
안녕하세요.
오늘은 C에서 파일 스트림을 열고 특정 위치로 이동하여 데이터를 읽거나 버퍼를 쓰는 방법에 대해 알아보겠습니다.
우리가 파일을 열고 쓰는 예제를 생각해보면 fopen 함수로 파일 디스크립터를 얻고 fwrite 함수를 통해 버퍼를 씁니다. 그러면 무조건 파일의 맨 처음 부분에 데이터가 쓰이는데, 만약에 이미 100 글자를 썼는데 다시 30번째부터의 데이터를 바꾸고 싶다면 어떻게 해야 할까요?
다음으로 만약 fopen 함수로 기존 파일을 열고 fread 함수를 호출하면 제일 앞의 데이터를 버퍼로 읽어옵니다. 그렇다면 처음 부분부터 읽지 않고 중간 부분부터 읽을 수는 없을까요?
바로 이러한 호기심을 해결해주는 함수가 fseek 입니다.
이 함수는 파일의 읽기 또는 쓸 위치를 원하는 곳으로 이동시켜줍니다.
파일의 경우는 내가 생성하고 다른 사람이 읽을 수도 있지만 내가 다른 사람의 파일을 읽을 수도 있습니다. 따라서 그 사람이 어떤 사람인지 알 수 없기 때문에 서로 누가 먼저 쓸 것인지 읽을 것인지 정할 수 없겠죠.
그래서 C에선 이러한 함수를 미리 제공하고 있습니다. 다만 이 함수는 여러 가지 옵션에 따라 차이점이 존재하기 때문에 그 특징을 이해하고 넘어갈 필요성이 있습니다.
지금까지의 내용을 종합하면 "fseek는 파일 스트림의 현재 위치를 이동시켜준다"가 되겠습니다.
오늘 포스팅의 예제를 따라 하기에 앞서 fopen, fclose 등의 파일 I/O 관련 함수에 대한 이해가 필요합니다. 파일 내용을 쓰기 위해선 파일을 생성할 줄 알아야 하기 때문입니다.
따라서 해당 함수 사용법을 아직 잘 모르고 있다면 아래 포스팅을 참고하시면 훨씬 이해하기 쉽습니다.
자 그러면 fseek 함수가 어떻게 생긴 함수인지 먼저 알아보도록 하겠습니다.
함수 구조
함수가 포함된 헤더
stdio.h
함수원형
int fseek(FILE *stream, long int offset, int origin);
인자
stream: 파일 스트림 포인터
offset: 3번째 인자의 origin 위치로부터 얼마나 이동할 것인가에 대한 값
origin: 이동을 어디부터 시작할 것인가에 대한 옵션. 아래와 같은 매크로 옵션이 존재함
- SEEK_SET: 파일의 시작점부터
- SEEK_CUR: 현재 파일을 마지막으로 읽은 시점부터
- SEEK_END: 파일의 마지막점부터
반환
0: 파일 오프셋 이동 성공
이외: 실패
파일의 시작점부터 원하는 위치까지 계산하여 문자열 출력 예제(fseek SEEK_SET 사용)
#include <stdio.h>
#include <string.h>
int create_example_file()
{
int r = 0;
const char *text = "안녕하세요.\n\
저는 개구리입니다.\n\n\
저는 흔들리는 연못에 삽니다.\n\
저는 캄캄한 하늘 속에 있습니다.\n\n\
저의 바램은 별의 탄생입니다.";
FILE *w_file = NULL;
w_file = fopen("test.txt", "w");
if (!w_file) {
printf("파일 열기 실패\n");
r = -1;
}
if ((int)fwrite(text, strlen(text), 1, w_file) < 1) {
printf("파일 쓰기 실패\n");
r = -1;
}
cleanup:
if (w_file) fclose(w_file);
return r;
}
int main()
{
int r;
char buf[512] = {0,};
FILE *r_file = NULL;
if (create_example_file < 0) goto onerror;
r_file = fopen("test.txt", "r");
if (!r_file) {
printf("읽기 전용 파일 열기 실패\n");
goto onerror;
}
r = fseek(r_file, 132, SEEK_SET);
if (r) {
printf("파일 오프셋 이동 실패\n");
goto onerror;
}
r = fread(buf, 40, 1, r_file);
if (r < 1) {
printf("문자열 읽기 실패\n");
goto onerror;
}
printf("읽기 결과 : %s\n", buf);
return 0;
onerror:
if (r_file) fclose(r_file);
return -1;
}
라인 설명
4-28: 매번 예제에서 파일을 생성하는 함수를 호출하기 어려워 예제 텍스트 파일을 생성하는 함수를 구현하였습니다.
38: fopen을 'r' 읽기 전용 모드로 생성한 예제 텍스트 파일을 엽니다. 이렇게 fopen시 최초 파일 오프셋은 파일의 시작점인 0입니다.
44: fseek 함수를 호출합니다. 인자로는 파일 스트림 포인터와, 132 값, SEEK_SET 매크로 값을 전달합니다. 각 인자의 의미는 아래와 같습니다.
(r_file): 파일 스트림 포인터
(132): 파일의 처음 시작점부터 "나의 바램은 별의 탄생입니다." 문자열의 시작점인 "나" 문자 위치까지의 거리는 132 바이트입니다. 따라서 132를 인자로 전달하였습니다. 왜냐하면 세 번째 인자인 SEEK_SET가 파일의 시작점부터 오프셋을 이동시키겠다는 의미이기 때문입니다.
(SEEK_SET): 파일의 시작점부터 이동시키겠다는 매크로 값입니다.
50: 44번 라인에서 fseek를 통해 현재 파일의 오프셋을 이동시켰기 때문에 fread로 "나의 바램 별의 탄생입니다." 문자열의 크기인 40을 인자로 전달하여 버퍼에 읽어옵니다.
56: 버퍼 내용을 printf 함수로 출력합니다.
결과를 확인해보겠습니다.
마무리
오늘은 fseek 함수를 사용하여 파일의 특정 위치부터 시작한 문자열을 출력하는 방법에 대해 알아보았습니다. 다음 포스팅에서는 fseek의 origin 인자인 SEEK_CUR, SEEK_END 값의 사용방법에 대해 추가적으로 알아보도록 하겠습니다.
관련 글
C 관련 포스팅 목록
2021.12.05 - [C/stdio] - C 파일 실시간 쓰기 예제(stdio/fflush)
2021.12.01 - [C/stdio] - C 파일 생성 및 스트림 열기 예제(stdio/fopen)
2021.11.30 - [C/stdio] - C 파일 스트림 닫기(stdio/fclose)