WinAPI 54 파일 입출력 (1)

CJB_ny·2022년 9월 30일
0

WinAPI

목록 보기
56/79
post-thumbnail

오늘 배운거 👍👍👍

  • 파일 입출력의 개념

  • c_str() 함수

  • w, wb 차이점 r, rb차이점

  • fwrite가 왜 void* 받고 사이즈를 받는지.


파일 입출력 (1)

그림판에 작업을 한 그 그림을 파일로 저장을 시키고 나중에 컴퓨터를 껏다 키든 뭐든

내가 작업했던 부분을 다시 불러올 수 있다.

근데 이게 가능한 이유가 메모리의 '비트 맵'에다가 픽셀(3바이트짜리) 데이터를 넣은 것이다.

그때 그 메모리들은 저장장치(SSD)에 있는게 아니라 시스템 메모리(RAM)에 존재하는 것이다.

컴퓨터가 꺼져있을 때 -> 켜져 있을 때, 저장 장치에 있던 데이터들을 '메모리'에 올리면서 RAM에 올라가 있는 데이터를

출력장치인 모니터를 통해서 보고있는 것이다.

실행중인 모든 데이터들이 RAM에 들어있는 것이다.

RAM이라는 장치는 전원이 꺼지면은 데이터들이 초기화가 된다.

그래서 '영구 저장 장치'에다가 데이터들을 저장해놓지 않으면 실행되던 모든 데이터들을 '소실' 하게된다.

RAM에서 작업을 하다가 적절한 시점에 중간중간 저장을 해두어야 컴퓨터를 껏다 키더라도 저장되어있는 데이터들을 다시 RAM에 불러와서 사용이 가능 할 것이다.

우리는 타일의 배치 및 구성을 저장을 해놓아야 똑같이 불러올 수 있다는 것이다.

ToolScene

에서는 타일을 저장하는 기능을 만들고 파일을 읽어오는 함수는 Scene에 있어야한다.

그래서 각각 SaveTile만들고 StartScene에서는 Enter 할시 자신에게 맞는 타일을

LoadTile로 불러온다.

ToolScene애서는 각각의 scene에 맞게 타일을 제작을 해서 저장을 하는 것이고.

확장자 개념 ❗❗

.txt, .json처럼 확장자가 있다고해서 안에 파일의 내용이 달라지거나 하지는 않는다.

어떤 종류의 데이터인지를 나타내주는 역할을 하는 것이다.

.mp4의 데이터의 확장자를 png로 바꾸면 안열리는 이유가

png파일을 여는 프로그램이 해당 데이터를 png파일로 인식을 해서 열려니까 png파일을 읽는 규칙에 맞지가 않아서 열리지 않는 것이다.

안에 들어있는 데이터는 mp4에 맞는 규칙에 따라 데이터가 들어가 있기 때문에

실제 파일의 정체와 확장자가 매칭이 되어야 한다.

우리 프로그램에서만 사용할 확장자는 .tile 확장자로 사용을 할 것이다.

알려진 확장자가 아니다.

구현할 부분

왼쪽 쉬프트 누르면 .tile확장자로 타일 데이터를 저장을 하는 부분을 구현을 해보도록 하겠다.

왼쪽에 RAM데이터를 실제 저장장치에 한땀한땀 데이터를 옮겨야한다.

시스템 메모리(RAM) 저장장치에 저장할려면은 '연결'을 해주어야한다.

  1. 파일 자체가 먼저 존재해야한다.

  2. 그곳과 실행중인 프로그램 사이에서의 '연결'작업 필요

stream -> Byte단위로 옮겨야한다.

파일 입출력 ❗

이게 바로 '파일 입출력'이다.

C++에서 제공하는 대표적인 파일 입출력함수가 fopen인데 우리는 지금 wstring 2byte문자열을 사용하기 때문에

_wfopen_s()이다.

이 함수는 인자로 '이중 포인터' 요구함.

이중 포인터 ❗❗❗

포인터 안에 포인터

인자값을 int 포인터 변수를 줄 경우 int포인트 변수가 변경되고 싶다면은

주소값변수명데이터 타입데이터(값)
0x1000a포인터nullptr(0x2000이런식)

이 a라는 int 포인터 변수가 변경되기를 원하는 것이니까

Test함수는 int가 아니라 int타입의 * 주소를 가져와야한다.

a가 가르키는 값이 수정되기를 원하니까

=> void Test(int** a) 가 되어야 한다.

int 자료형 하나만큼 동적할당해서 *a에다가 넣어줌.

주소값변수명데이터 타입데이터(값)
0x1000a포인터0x1234 (힙에 동적할당 된 int 주소값

FILE 기능

  • 커널 오브젝트이다.

  • 저장 장치와 프로그램 사이의 연결을 잡아주는 역할을 한다.

=> 파일이 생성 되었다라는 것은 stream(연결)이 잘 열렸다는 것이다.

이렇게 stream이 잘 열려서 연 file의 주소값을 FILE* 로 받아 올 수 있다는 것이다.

FILE이라는 커널오브젝트를 내가 직접 삭제할 필요는 없는데

stream이 잘되서 파일 불러오면은 이제 stream을 닫는 작업이 필요하다.

해당 부분도 Win에서 제공을 해준다.

FILE 1개 == stream 1개

FILE하나가 stream하나를 대변한다고 생각하면은 된다.

여러개 FILE을 열 수 있으니까.

경로

운영체제는 우리의 '상대 경로'가 아니라 '절대 경로'를 필요로 한다.

c_str() ❗❗❗

https://jayy-h.tistory.com/5#:~:text=String%20class%EC%9D%98%20%EB%A9%A4%EB%B2%84%ED%95%A8%EC%88%98%EC%9D%B8%20c_str()%EC%9D%80%20%EC%9B%90%EB%B3%B8,%EC%82%AC%EB%9D%BC%EC%A7%80%EB%8A%94%20%EC%88%9C%EA%B0%84**%20%EB%AC%B4%ED%9A%A8%ED%99%94%20%EB%90%9C%EB%8B%A4.

String class의 멤버함수인 c_str()은 원본 객체가 담고있는 문자열에 대해 const char* 타입을 리턴한다. 하지만 이 값은 원본 객체인 string이 메모리를 재할당받거나 string 객체가 사라지는 순간 무효화 된다.

즉 _wfopen_s의 두번째 인자로는 filePath의 주소값을 넣어준 셈이다.

w 모드

메모리에 있는 데이터를 저장장치 쪽으로 '쓴다 == write'

현재 w 모드일 경우 거꾸로 저장장치에서 RAM쪽으로 읽어오는게 불가능 하다.

r 모드

저장장치에 있는 데이터를 시스템 메모리(RAM)쪽으로 '읽는다 == Read'

이것 말고도 파일 입출력의 모드에 따라서 의미가 다양하게 있다.

현재 상황

w모드 상황인데 파일이 있지도 않는데 쓴다?

=> 파일이 없다면은 w모드 일 경우 파일을 만들어 버린다.

보면은 0KB짜리 빈껍데기 파일이 만들어져있다.

b 유무 ?? ❗❗❗

write하는데 binary 모드로 쓰겠다라는 것인데

b가 뭐냐?

=> 우리가 저장하는 데이터는 0과 1로 이루어진 비트 덩어리 이다. -> 8개 모이면은 1바이트이고

그냥 이런 바이트 데이터를 쓰겠다라는 말이다.

그러면 b를 안 붙이면은??

똑같이 Binary데이터를 읽거나 쓰는거는 똑같음. -> 당연히 데이터는 0, 1로 이루어져 있으니까

b를 근데 안붙이면은 기본적으로 읽거나 쓰는 데이터를 '문자 데이터'로 기본적으로 가정을 한다.

그래서 내가 숫자 3을 저장하더라도 3에 대응하는 아스키 코드값을 저장한다고 인식을 하는 것이다.

그래서 숫자 100을 저장하는데에 w나 wb나 상관은 없을 거 같지만

27이라는 숫자에 해당하는 아스키 코드가 ESC이다.

Escape 탈출 문자로 본다.

하필이면은 캐릭터의 공격력이 27인데 이 파일을 읽다가

27이네? => Escape이네? 하고 파일이 닫힌다. 문자로 인식을 해서 그것을 '종료'라고 받아 들이기 때문이다.

그래서 저장하는 데이터를 순수한 2진수 데이터로 보자 해서 'wb'를 사용하는 것이다.

어떻게 저장?

이렇게 타일 맨들어 놓고 다시 파일 열었을때 이게 똑같이 열려야됨.

어케함?

buffer를 먼저 받는데 저장될 데이터의 시작 주소를 말하는 것이다.

fwrite가 어떠한 상황에서도 다 적용되어야하기 때문에 void*로 받아갔다.

sizeof(UINt) 만큼, 한개만, stream은 열려있는 file.

읽는 부분

fread를 통해서

이렇게 읽을 것이다.

문제 ❗❗❗

타일 갯수를 변경한 다음에 저장 -> 잘됨

프로그램 종료후 다시 열어서 -> 컨트롤 키 -> 잘 열림 -> 타일갯수도 저장한 타일이랑 같음.

다만 문제점이 발생을 하는데 클릭시 좌표가 이상함.

타일을 불러왔을 때가 문제임.

CreateTile을 할 때 기존의 타일들을 다 지워 줘야함. => 안지우면은 배열의 인덱스가 다 꼬여버림.

해당 문제는

이렇게 CreateTile할때 기존에 것들 다 날리고 하면은 문제 없어진다.

다른 데이터 저장

이제 타일의 갯수를 저장 하는 부분은 Ok.

이제 각각의 타일들이 가지는 이미지 texture를 저장을 해아한다.

이것을 Save하는 곳에서 싹다 분기 처리를 할 수는 없고

Tile들이 알아서 해야하는 부분들이다.

Tile파일에서 SaveInfo, LoadTile다 만들어서 필요한 정보를 저장을 해주도록 하자.

타일은 무엇을 저장해야하냐면은

타일 텍스쳐의 인덱스 번호를 저장하고 있어야한다.

텍스쳐 파일은 하나만 사용하기로 했으니까

이런식으로 저장하고 불러오면은 된다.

profile
https://cjbworld.tistory.com/ <- 이사중

0개의 댓글