오늘의 TIL 목차 (22.08. 12)
- 파일 입출력
- 파일 입출력 지원 함수
- 바이너리 입출력 지원 함수
파일 입출력
[ 파일 입출력 ]
fopen_s(FILE** _Stream, char const* _FileName, char const* _Mode);
fopen_s(파일 포인터의 주소(파일 핸들), 파일 경로, 모드);
FILE* fp = nullptr;
errono_t fInput = fopen_s(&fp, "..\C220812\Text.txt", "wt");
// C220812 폴더 안에 텍스트 모드의 쓰기 파일 Text.txt 생성
// errono_t 자료형 fInput에 대입하는 이유는 파일 생성 성공 여부 확인을 위해서
▶ errono_t 자료형
: 다양한 함수의 반환 값으로 사용되며 값이 0이면 성공, 값이 0이 아니면 실패를 의미한다. ( C 시절의 bool 대체품형 int )
▶ 경로
- 절대 경로 : 드라이브 명에서 현재 파일이 있는 위치까지를 표현하는 경로
- 상대 경로 : 프로젝트 파일을 기준으로 찾고자 하는 파일이 있는 위치까지를 표현하는 경로
☞ 해당 VS 파일을 기준으로 ../ 는 상위 폴더 ./ 는 현재 폴더 / 는 최상위 폴더이다.
D:\Code\P220812
-> D드라이브 > Code > P220812 라는 현재 작업 중인 VS 파일을 기준으로
D:\Code\C220812 의 위치에 Text.txt 파일을 생성하고 싶다면.
..\ 로 상위 폴더인 Code로 나와서 /로 Code 안의 C220812로 접근
-> ..\C220812\Text.txt // C220812 안에 Text 파일 생성
※ 비쥬얼스튜디오의 경우 .vcxproj 파일을 기준으로 상대경로
▶ 모드
w (write, 쓰기), r (read, 읽기), a (add, 추가)
t ( text, 텍스트 모드 ), b ( binaray, 바이너리 모드 )
-> 이 두개를 혼용하여 사용한다. ex) wt, rb ,,,
▶ 파일 입출력 순서
1. 파일을 개방 : 스트림을 생성 -> '파일 핸들'을 개방
2. 파일 쓰기, 읽기
3. 파일을 소멸 - fclose(파일); 필수
파일 입출력 지원 함수
1. fseek() 2. ftell() 3. feof()
[ fseek() ]
: 커서를 강제를 이동시키는 함수
fseek(파일 스트림, 이동할 바이트 수, 이동할 시작 지점) // int형
※ 이동할 시작 지점 ( 에 들어갈 종류 )
- SEEK_SET (1) : 파일의 처음 위치
- SEEK_CUR (2) : 현재 파일의 커서 위치
- SEEK_END (3) : 파일의 끝 위치
[ ftell() ]
: 커서의 위치를 알려주는 함수, 0부터 이동하여 몇 번째 위치에 있는지 인덱스 값을 반환
ftell(파일 스트림); // long형
[ feof() ]
: 파일 지시자가 eof에 도달했는지 알려주는 함수. eof에 도달한 경우 0이 아닌 값을 반환 = 0이면 참
if( 0 == feof(fP)) // fp 파일이 eof를 만나지 않았다면 0 반환 , int형
■ 예시
FILE* fpWrite = nullptr;
FILE* fpRead = nullptr;
errno_t errWrite = fopen_s(&fpWrite, "../TEXT.txt", "at");
if (0 == errWrite) // 0은 성공적
{
cout << "쓰기 파일 개방 성공" << endl; // (파일스트림, 이동할 바이트 수, 시작지점)
fseek(fpWrite, 0, SEEK_CUR); // 커서의 위치 처음을 옮기기
cout << ftell(fpWrite) << endl;
// 커서 위치를 옮겨도 at 추가입력은 뒤에서부터 되는 듯함
char* szName = new char[25];
// cin >> szName; // cin 또는 get_s로 입력 시 배열의 크기를 넘어가도 입력되는 오버로드 발생 (오류)
// fgets는 자동개행 해줌, cin이나 일반 입력 함수는 개행 지원 X
// fgets는 띄어쓰기까지 인식, cin으로 받는 문자열, 문자배열은 띄어쓰기 전까지 인식
fgets(szName, 25, stdin); // (배열명(=주소), 크기, 스트림)
fputs(szName, fpWrite); // fpWrite에 szName 문자열을 출력
cout << "쓰기 파일 완료" << endl;
fclose(fpWrite);
}
else
cout << "쓰기 파일 실패" << endl;
errno_t errRead = fopen_s(&fpRead, "../TEXT.txt", "rt"); // 파일 생성이 되야 읽기로 접근 가능
if (0 == errRead)
{
cout << "파일 읽기 접근" << endl;
//char sRead[25] = {};
//fgets(sRead, sizeof(sRead), fpRead); // fpRead 파일로부터 sizeof만큼 sRead에 읽어옴
//fputs(sRead, stdout); // 내용이 추가되어도 sRead 크기만큼만 읽어오는 문제 발생
char ch = {};
while (0 == feof(fpRead)) // eof에 도달한 경우 0이 아닌 값 반환
{
ch = fgetc(fpRead);
fputc(ch, stdout); // 콘솔에 ch 출력
}
cout << endl;
cout << "파일 읽기 성공" << endl;
fclose(fpRead);
}
else
{
cout << "읽기 실패" << endl;
}
☞ EOF를 만날 때까지 while문을 돌려 getc(), putc() 방식을 사용하는 이유 : 단순 fgets, fputs로 파일을 읽어와 출력하면 쓰기 파일에 내용이 추가되었어도 fgets한 문자열의 크기만큼만 읽어와 출력됨
파일 입출력 바이너리 모드
[ 파일 입출력 바이너리 ]
: 바이너리 파일 확장자 .dat , 텍스트 파일 확장자 .txt
// 바이너리 출력 함수 :
fwrite(출력할 메모리 시작 주소, 출력할 메모리 크기, 출력할 메모리 개수, 스트림)
// 바이너리 입력 함수 :
fread(출력할 메모리 시작 주소, 출력할 메모리 크기, 출력할 메모리 개수, 스트림)
-
■ 예시 ( TextRPG )
void Save(tObj* _pPlayer) // 플레이어 정보 저장
{
FILE* fpSave = nullptr;
errno_t err_Save = fopen_s(&fpSave, "../SaveRPG.dat", "wb");
if (0 == err_Save) // 파일 성공
{
fwrite(_pPlayer, sizeof(tObj), 1, fpSave);
cout << "저장 성공" << endl;
fclose(fpSave); // 파일 닫기 필수
}
else
{
cout << "저장 실패" << endl;
}
system("pause");
}
// pPlayer 포인터만 받아오면 pPlayer의 값인 주소 nullptr이 복사되어 nullptr 주소에 값을 넣고 소멸됨
// 이중포인터로 pPlayer 자체의 주소를 가져와서 안의 값 nullptr에 동적할당한 주소를 넣고 값을 변경해줘야됨
void Load(tObj** _pPlayer)
{
FILE* fpLoad = nullptr;
*_pPlayer = new tObj; // 파일을 읽어서 저장하기 위해선 _pPlayer에 메모리 공간 필요(현재 할당 안된 상태)
errno_t err_Load = fopen_s(&fpLoad, "../SaveRPG.dat", "rb");
if (0 == err_Load) // 파일 불러오기 성공
{
fread((*_pPlayer), sizeof(tObj), 1, fpLoad);
cout << "불러오기 성공" << endl;
fclose(fpLoad);
}
else
{
cout << "불러오기 실패" << endl;
}
system("pause");
}'C++' 카테고리의 다른 글
| [TIL 18장] OOP의 개념(+추상화), 클래스(4대 속성), 클래스 속성 - 은닉화(feat. 접근 제어 지시자), 파일 분리 (클래스 - 선언부 구현부) (0) | 2022.08.29 |
|---|---|
| [TIL 16장] 레퍼런스 (0) | 2022.08.18 |
| [TIL 14장] 메모리 함수, 콘솔/파일 입출력 함수[text] (0) | 2022.08.12 |
| [TIL 13강] 열거체, C언어 동적할당(feat. Heap) (0) | 2022.08.12 |
| [TIL 12장] 문자열 함수, 구조체(feat. 포인터 사용), 공용체 (0) | 2022.08.10 |