파일 I/O와 디렉터리 컨트롤
파일 I/O와 관련된 ANSI 표준 함수를 사용하면 운영체제의 종류에 상관없이 파일이 생성되고 파일에서 데이터를 가져오고 I/O 연산을 수행할 수 있다. H/W 가 있는데 이 하드웨어에 운영체제로 윈도우, 리눅스, 유닉스를 설치할 수 있다. 그다음 운영체제 위에서 프로그램을 동작시킨다. 프로그램을 동작시킬 때 각 운영체제에서 파일을 생성한다. 중요한 사실은 파일이 저장이 될 때 저장되는 방식은 파일 시스템에 의존적이다.
파일이라는 것 자체를 어떻게 정의하고 구성할 것이냐? 파일 시스템은 운영체제의 일부이다.
즉 파일 시스템은 운영체제에서 구현하고 있는 독립적인 시스템이다.
그래서 호출할 때 ANSI 표준 함수를 호출하지만 실제 파일을 만드는 대상은 운영체제들이다.
윈도우에서 파일을 만들면 윈도우가 만드는 거다. 리눅스에서 만들면 리눅스가 만드는 거다.
call을 했을 때 파일이 만들어지는 과정을 보자.
ANSI 표준 함수가 구현되기 이전에 시스템 함수가 완성이 된다.(공부했던 내용들이 대부분 다 시스템 함수다.)
윈도우 운영체제에서 파일을 만들려면 파일과 관련된 시스템 함수들이 필요하다.
그러면 ANSI 표준 함수로도 만들 수 있고 시스템 함수를 통해서 만들 수 있는데 그러면 그 사이에 차이점이 뭐냐
ANSI 표준 함수가 실제로 파일을 만드는 게 아니고 내부적으로 시스템 함수를 호출해서 파일을 생성한다.
ANSI 표준 함수에서 제공하는 것은 모든 운영체제의 대표적인 공통분모만 함수로 제공한다.
개발할 때 각 운영체제에 의존적인 파일 시스템 함수를 호출할 필요도 있을 수 있다.
그런 경우 각 운영체제에서 제공하는 시스템 함수를 사용하면 된다.
이런 식으로 ANSI 표준 함수와 각 운영체제의 시스템 함수의 차이점을 알 수 있을 거다.
파일 관련 기본 함수들
- 파일 생성
- CreateFile
- 입력 및 출력
- ReadFile, WriteFile
- 파일종료
- CloseHandle
- 위 함수를 사용한다는 의미는 파일 생성해도 커널 오브젝트가 생성이 되고 해당 커널 오브젝트의 핸들이 반환된다. 즉 파일은 커널에서 관리하는 리소스다.
- 왜 파일이 커널에서 관리하는 리소스냐면 파일 포인터란 어디까지 그 정보를 읽었는지 가지고 있다. 따라서 이 파일 포인터를 컨트롤한다. 이런 것들은 자동적으로 커널에 의해서 관리되는 것들이다.
파일 정보 얻어오기
파일 정보를 얻을 때 2가지를 고려해야 한다.
하나는 핸들을 통해 얻을 것인가 아니면 이름을 통해 얻을 것인가 이 두 가지를 고려해야 한다.
- GetFileTime
- 만든 날짜, 수정한 날짜, 액세스 한 날짜
- 핸들을 통해 정보 확인
- GetFileAttributes
- 읽기 전용, 숨김, 보관
- 파일 이름을 통해 정보 확인
- GetFileInformationByHandle
- 위 두 함수를 통해 얻을 수 있는 정보 모두 얻을 수 있다.
- 핸들을 통해 정보 확인
파일 포인터 이동
fseek() → 파일 포인터를 이동하는 함수
32bit 기반에서는 파일 최대 크기가 4G보다 작으면 32bit로 표현이 가능하다.
4GB 보다 크면 32bit로 표현이 안되기 때문에 64bit 시스템에서만 4GB 이상의 파일을 만들 수 있다.
메모리에 파일을 저장할 때 왜 32bit 시스템에서는 파일의 크기가 4GB까지 허용이 안 되는가?
파일 주소 3GB 번지에 있는 것을 가져오려면 3GB를 표현해야 한다. 4GB까지 표현을 하려면 32bit가 있어야 한다.
32bit로 표현할 수 있는 주소의 최대 크기는 4GB - 1이다.(0부터 시작한다고 했을 때) 그렇기 때문에 4GB까지밖에 표현이 안되는 거다.
- SetFilePointer
- 첫 번째 인자는 파일 포인터를 옮기고 싶은 파일의 핸들 정보
- 두 번째 인자는 0 ~ 4GB - 1
- 세 번째 인자 그 이상의 값
- 네 번째 인자는 어디서부터 옮길 거냐
- 64bit 시스템에서는 8바이트 단위로 데이터를 넘긴다 그래서 0 ~ 4바이트는 두 번째 인자를 통해서 그다음 4 ~ 8바이트는 세 번째 인자로 전달된다.
- 32bit에서는 세 번째 인자로 null로 두면 되지만 64bit에서는 2,3번째 인자 모두 써야 한다.
- 중요한 사실은 32bit에서는 파일의 최대 크기가 4G 바이트 - 2이다.
- 2^32가 4GB다. 주소는 항상 0부터 시작한다. 그렇기 때문에 32bit로 표현할 수 있는 주소의 범위는 0 ~ 2^32 - 1 즉 0 ~ 4GB - 1까지 인덱싱을 해줄 수 있다.
- 마지막 주소값이 파일의 크기가 된다. 따라서 실제 파일의 크기는 4GB - 1이 돼야 할 텐데 문제가 있다. SetFilePointer를 호출했을 때 오류가 발생이 되면 오류가 발생됐다는 것을 시그널로 알려준다. 0부터 표현할 수 있는 값의 크기가 4GB - 1까지인데
- 32bit로 표현할 수 있는 주소의 범위가 0 ~ 2^32 - 1 번지까지다. 따라서 실제 파일의 크기는 최대 4GB - 1까지 생성할 수 있는데 문제는 파일 관련된 I/O 함수를 호출했을 때 오류가 발생하면 INVALID_SET_FILE_POINTER(OxFFFFFFFF)라는 상수 값을 반환한다. 근데 이때 반환한 값인 0xFFFFFFFF값은 4G - 1이다. 그래서 파일의 크기를 4G - 1까지 허용을 해버리면 4G - 1이 반환 됐다고 했을 때 이 값이 INVALID_SET_FILE_POINTER 의미하는 건지 아니면 파일의 실제 크기를 의미하는 건지 혼란스럽다. 이러한 문제를 해결하기 위해 4G - 1라는 숫자를 오류를 의미한다고 약속을 했다. 즉 따라서 실제 생성할 수 있는 파일의 크기는 4G - 2로 제한된다.
- 64bit 기반
- SetFilePoinrter() 함수는 파일 포인터의 현재 위치를 반환한다.
- 하위 4바이트는 반환값을 통해 얻고 상위 4바이트는 세 번째 전달인자를 통해서 얻을 수 있다. 실제 크기를 계산하기 위해서는 위 두 개를 묶어줘야 한다.
'운영체제 > 뇌를 자극하는 윈도우즈 시스템 프로그래밍' 카테고리의 다른 글
뇌를 자극하는 윈도우즈 시스템 프로그래밍 20장 (0) | 2024.09.22 |
---|---|
뇌를 자극하는 윈도우즈 시스템 프로그래밍 19장 (2) | 2024.09.22 |
뇌를 자극하는 윈도우즈 시스템 프로그래밍 16장 (5) | 2024.09.22 |
뇌를 자극하는 윈도우즈 시스템 프로그래밍 15장 (0) | 2024.09.21 |
뇌를 자극하는 윈도우즈 시스템 프로그래밍 14장 (0) | 2024.09.21 |