[코딩도장] Unit 71
1. 파일 포인터 활용하기 (fseek, ftell)
1. 파일 포인터 이동하기 (fseek)
fseek 함수는 기준점에서 이동할 거리(크기)를 지정하여 파일 포인터를 이동시킨다
- fseek(파일포인터, 이동할크기, 기준점)
fseek(fp, 0, SEEK_END); // 파일 포인터를 파일의 끝으로 이동시킴
fseek 의 기준점은
- SEEK_SET 파일의 처음부터 시작
- SEEK_CUR 현재 위치부터 이동 시작
- SEEK_END 파일의 끝부터 시작
SEEK_SET, SEEK_CUR, SEEK_END는
기준점을 기준으로 파일 포인터의 위치를 바꾼다
fseek(fp, 0, SEEK_SET); 이면 파일의 처음으로 간다
fssek(fp, 0, SEEK_END); 이면 파일의 끝으로 간다
현재 위치에서 순방향으로 10바이트 이동하려면
fseek(fp, 10, SEKK_CUR); 과 같이 10바이트만큼 순방향으로 이동하도록 하면 된다
역방향으로 10바이트 이동하려면
fssek(fp, -10, SEEK_CUR); 과 같이 음수를 지정하면 된다
파일 포인터의 이동 방향은 포인터 연산의 이동 방향과 같다
2. 파일 크기 구하기 (ftell)
파일포인터의 현재 위치를 얻어오려면 ftell 함수를 사용하면 된다
- ftell(파일포인터)
size = ftell(fp); // 파일 포인터의 현재 위치를 얻음
이동할 크기를 0으로하고 기준점을 SEEK_END로 지정하여
ftell 함수를 사용하면 파일의 크기를 알 수 있다
fseek(fp, 0, SEEK_END); // 파일 포인터를 파일의 끝으로 이동시킴
size = ftell(fp); // 파일 포인터의 현재 위치를 얻음
2. 파일 크기만큼 파일 읽기
1. 파일 크기만큼 파일 읽기
FILE *fp = fopen("hello.txt", "r"); // hello.txt 파일을 읽기 모드(r)로 열기.
// 파일 포인터를 반환
fseek(fp, 0, SEEK_END); // 파일 포인터를 파일의 끝으로 이동시킴
size = ftell(fp); // 파일 포인터의 현재 위치를 얻음
fopen 함수로 파일을 읽기 모드로 열고
fseek 함수와 ftell 함수로 파일의 크기를 구한다
buffer = malloc(size + 1); // 파일 크기 + 1바이트(문자열 마지막의 NULL)만큼 동적 메모리 할당
memset(buffer, 0, size + 1); // 파일 크기 + 1바이트만큼 메모리를 0으로 초기화
파일의 문자열을 읽어서 C언어 문자열로 만들 때는
문자열 마지막의 NULL 공간까지 확보해야 한다
따라서 파일 크기 + 1바이트만큼 메모리를 할당한다
malloc 함수로 할당한 메모리는 memset 함수를 사용하여 0으로 초기화 한다
할당한 메모리를 NULL 로 초기화하지 않으면
문자열 끝 부분에 다른 값이 들어있을 수도 있다
문자열의 끝인 NULL을 찾을 수 없어 문자열 이외의 값이 함께 출력되므로 주의해야 한다
fseek(fp, 0, SEEK_SET); // 파일 포인터를 파일의 처음으로 이동시킴
count = fread(buffer, size, 1, fp); // hello.txt에서 파일 크기만큼 값을 읽음
파일의 크기를 구할 때 파일 포인터를 끝으로 이동시켰다
이 상태에서는 파일을 읽을 수 없기 때문에
fseek 함수를 이용하여 파일 포인터를 맨 처음으로 이동시킨다
printf("%s size: %d, count: %d\n", buffer, size, count);
// Hello world! size: 13, count: 1: 파일의 내용, 파일 크기, 읽은 횟수 출력
printf 로 버퍼의 내용을 출력하면 파일의 내용이 출력된다
fclose(fp); // 파일 포인터 닫기
free(buffer); // 동적 메모리 해제
파일 읽기가 끝났으면 파일 포인터를 닫고 메모리를 해제한다
2. 제한된 버퍼로 파일 전체 읽기 (feof)
feof 함수는 현재 파일 포인터가 파일의 끝인지 검사한다
- feof(파일포인터)
while (feof(fp) == 0) // 파일 포인터가 파일의 끝이 아닐 때 계속 반복
feof 함수는 파일 포인터가 파일의 끝이면 1을 반환 아니면 0을 반환한다
char buffer[5] = { 0, }; // 문자열 데이터 4바이트 NULL 1바이트. 4 + 1 = 5
버퍼 크기를 5바이트로 만들어준다
문자열을 읽어서 출력할 것이기 때문에 문자열 4바이트 NULL 1바이트이다
while (feof(fp) == 0) // 파일 포인터가 파일의 끝이 아닐 때 계속 반복
{
count = fread(buffer, sizeof(char), 4, fp); // 1바이트씩 4번(4바이트) 읽기
printf("%s", buffer); // 읽은 내용 출력
memset(buffer, 0, 5); // 버퍼를 0으로 초기화
total += count; // 읽은 크기 누적
}
while 반복문에 조건식으로 feof(fp) == 10 을 지정하여
파일 포인터가 파일의 끝이 아닐 때 계속 반복하도록 한다
fread 함수로 파일을 읽을 때는 buffer 를 선언한 자료형이 char 이기 때문에
sizeof(char)를 지정하여 1바이트 크기로 4번 읽는다
fread 로 파일을 읽었을 때 읽은 크기만큼 반환값이 나오기 때문에 파일의 전체 크기를 구할 수 있다
fread 로 파일을 읽고 크기는 count에 저장한다
printf 로 buffer 의 내용을 출력한다
출력이 끝났다면 memset 함수로 buffer 를 초기화 한다
이렇게 한정된 버퍼를 이용해 전체 문자열을 출력할 수 있다
3. 심사문제
71.9 파일을 부분적으로 읽기
문자열이 저장된 words.txt 파일이 주어집니다. 다음 소스 코드에서 getData 함수를 완성하여 words.txt에서 읽은 문자열을 출력하고, 그 다음 줄에 읽은 크기를 출력하는 프로그램을 완성하세요.
정답에는 밑줄 친 부분에 들어갈 코드만 작성해야 합니다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int getFileSize(FILE *fp)
{
int size;
int currPos = ftell(fp);
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, currPos, SEEK_SET);
return size;
}
char *getData(int offset, int size, int *count, FILE *fp)
{
__________________________________
__________________________________
__________________________________
__________________________________
__________________________________
}
int main()
{
char *buffer;
int size;
int count;
FILE *fp = fopen("words.txt", "r");
size = getFileSize(fp);
buffer = getData(0, size, &count, fp);
printf("%s\n", buffer);
printf("%d", count);
fclose(fp);
free(buffer);
return 0;
}
정답
char *buffer;
buffer = malloc(size + 1);
memset(buffer, 0, size + 1);
fseek(fp, offset, SEEK_SET);
*count = fread(buffer, sizeof(char), size, fp);
return buffer;
71.10 파일을 부분적으로 읽기
문자열이 저장된 words.txt 파일이 주어집니다.(반드시 GitHub 저장소의 Unit 71/words.txt 파일로 테스트하세요.) 파일 처음부터 순방향으로 7바이트 지점에서 4바이트만큼 읽고, 파일 끝에서 역방향으로 6바이트 지점에서 2바이트만큼 읽은 값을 출력하는 프로그램을 만드세요. 단, 읽은 문자열은 공백으로 띄우지 않고 붙여서 출력합니다.
정답
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *readForword(char *buffer, int offset, int size, FILE *fp) {
if (feof(fp) == 1)
return NULL;
fseek(fp, offset, SEEK_SET);
fread(buffer, sizeof(char), size, fp);
return buffer;
}
char *readBackword(char *buffer, int offset, int size, FILE *fp) {
if (feof(fp) == 1)
return NULL;
fseek(fp, offset, SEEK_END);
fread(buffer, sizeof(char), size, fp);
}
int main() {
char forBuffer[20] = {0, };
char backBuffer[10] = {0, };
FILE *fp = fopen("words.txt", "r");
readForword(forBuffer, 7, 4, fp);
readBackword(backBuffer, -6, 2, fp);
strcat(forBuffer, backBuffer);
printf("%s", forBuffer);
fclose(fp);
return 0;
}
파일을 정방향으로 읽는 함수 readForword 를 작성하고
파일을 역방향으로 읽는 함수 readBackword 를 작성한다
두 함수를 이용해 문자열을 읽어온 뒤
두 문자열을 strcat 함수를 이용해 이어붙인다
71.11 파일을 읽은 뒤 거꾸로 저장하기
문자열이 저장된 words.txt 파일이 주어집니다. 파일을 읽은 뒤 내용을 거꾸로 저장하는 프로그램을 만드세요. 결과는 fwrite 함수로 stdout에 저장하면 됩니다. 단, words.txt 의 최대 크기는 10,000바이트입니다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int size, readSize;
char *buffer;
FILE *fp = fopen("words.txt", "r");
fseek(fp, 0, SEEK_END);
size = ftell(fp);
buffer = malloc(size);
while (size > 0) {
fseek(fp, -1, SEEK_CUR);
readSize = fread(buffer, sizeof(char), 1, fp);
fwrite(buffer, sizeof(char), 1, stdout);
fseek(fp, -1, SEEK_CUR);
size --;
}
free(buffer);
fclose(fp);
return 0;
}
fseek 함수를 이용해 파일 포인터를 맨 끝으로 이동시킨 후
문자열을 거꾸로 읽어와 버퍼에 저장한다
하지만 fread 함수는 순방향으로 1 이동하기 때문에
문자열을 읽어온 후 fseek 함수를 이용해 역방향으로 1 이동시켜줘야 한다
(아니면 제자리에서 무한 반복하는 문제가 발생한다)
'Coding > C' 카테고리의 다른 글
[C언어] 파일에서 문자열 읽고 쓰기 - 코딩도장 (0) | 2024.02.29 |
---|---|
[C언어] 함수 가변인자, 재귀호출 - 코딩도장 (0) | 2024.02.10 |
[C언어] 함수에서 매개변수 사용하기(포인터, 배열, 구조체) - 코딩도장 (0) | 2024.02.06 |
[C언어] 함수 사용하기 - 코딩도장 (0) | 2024.02.02 |
[C언어] 자료형 변환, 포인터 연산 - 코딩도장 (0) | 2024.01.30 |