파일 버퍼링
이 항목에서는 버퍼링되지 않은 파일 입력/출력(I/O)으로도 알려진 파일 버퍼링의 애플리케이션 제어에 대한 다양한 고려 사항에 대해 설명합니다. 파일 버퍼링은 일반적으로 백그라운드 시스템에서 처리되며 달리 지정하지 않는 한 Windows 운영 체제 내에서 파일 캐싱 일부로 간주됩니다. 캐싱 및 버퍼링 용어는 때때로 서로 교환적으로 사용되지만, 이 항목에서는 시스템에서 캐시(버퍼링)되지 않는 데이터와 상호 작용하는 방법을 설명하는 컨텍스트에서 버퍼링이라는 용어를 사용합니다. 그렇지 않으면 대부분 사용자 모드 애플리케이션을 직접 제어할 수 없습니다.
CreateFile 함수를 사용하여 파일을 열거나 만들 때 파일에서 읽거나 파일에 쓰는 데이터의 시스템 캐싱을 사용하지 않도록 FILE_FLAG_NO_BUFFERING 플래그를 지정할 수 있습니다. 이렇게 하면 데이터 I/O 버퍼링을 완전하고 직접 제어할 수 있지만 파일 및 유사한 디바이스의 경우 고려해야 할 데이터 맞춤 요구 사항이 있습니다.
메모
이 정렬 정보는 탐색을 지원하는 파일과 파일 위치 지시자(또는 오프셋)의 개념과 같은 디바이스의 I/O에 적용됩니다. 명명된 파이프 또는 통신 디바이스와 같이 검색하지 않는 디바이스의 경우 버퍼링을 해제하는 데 특정 맞춤이 필요하지 않을 수 있습니다. 이 경우 맞춤을 통해 얻을 수 있는 제한 사항 또는 효율성은 기본 기술에 따라 달라집니다.
간단한 예제에서 애플리케이션은 FILE_FLAG_NO_BUFFERING 플래그를 사용하여 쓰기 액세스를 위해 파일을 연 다음 애플리케이션 내에 정의된 데이터 버퍼를 사용하여 WriteFile 함수에 대한 호출을 수행합니다. 이 로컬 버퍼는 이러한 상황에서 이 작업에 존재하는 유일한 파일 버퍼입니다. 실제 디스크 레이아웃, 파일 시스템 스토리지 레이아웃 및 시스템 수준 파일 포인터 위치 추적으로 인해 로컬로 정의된 데이터 버퍼가 다음 섹션에서 설명하는 특정 맞춤 조건을 충족하지 않으면 이 쓰기 작업이 실패합니다.
메모
캐싱에 대한 논의는 물리적 디스크 자체에 대한 하드웨어 캐싱을 고려하지 않으며, 어떤 경우에도 시스템의 직접 제어 내에 있다고 보장되지 않습니다. 이는 이 항목에 지정된 요구 사항에 영향을 주지 않습니다.
FILE_FLAG_NO_BUFFERING 다른 캐시 관련 플래그와 상호 작용하는 방법에 대한 자세한 내용은 CreateFile참조하세요.
맞춤 및 파일 액세스 요구 사항
이전에 논의한 것처럼, FILE_FLAG_NO_BUFFERING옵션으로 열린 파일과 작업할 때 애플리케이션은 특정 요구 사항을 충족해야 합니다. 다음 세부 사항이 적용됩니다.
- 지정된 경우 OVERLAPPED 구조의 선택적 파일 오프셋을 포함한 파일 액세스 크기는 볼륨 섹터 크기의 정수 배수인 바이트 수여야 합니다. 예를 들어 섹터 크기가 512바이트인 경우 애플리케이션은 512, 1,024, 1,536 또는 2,048바이트의 읽기 및 쓰기를 요청할 수 있지만 335, 981 또는 7,171바이트는 요청할 수 없습니다.
- 읽기 및 쓰기 작업에 대한 파일 액세스 버퍼 주소는 물리적 섹터 정렬이어야 합니다. 즉, 볼륨의 실제 섹터 크기의 정수 배수인 메모리의 주소에 정렬됩니다. 디스크에 따라 이 요구 사항이 적용되지 않을 수 있습니다.
애플리케이션 개발자는 실제 미디어 섹터 크기가 4,096바이트인 새로운 유형의 스토리지 디바이스가 시장에 도입되고 있음을 기록해 두어야 합니다. 이러한 디바이스의 업계 이름은 "고급 형식"입니다. 미디어 주소 지정 단위로 4,096바이트를 직접 도입하는 경우 호환성 문제가 있을 수 있으므로 임시 호환성 솔루션은 일반 512바이트 섹터 스토리지 디바이스를 에뮬레이트하지만 표준 ATA 및 SCSI 명령을 통해 실제 섹터 크기에 대한 정보를 제공하는 디바이스를 도입하는 것입니다.
이 에뮬레이션의 결과로 개발자가 이해해야 하는 두 가지 섹터 크기가 기본적으로 있습니다.
- 논리 섹터: 미디어의 논리 블록 주소 지정에 사용되는 단위입니다. 스토리지에서 허용할 수 있는 가장 작은 쓰기 단위로 생각할 수도 있습니다. "에뮬레이션"입니다.
- 물리적 섹터: 디바이스에 대한 읽기 및 쓰기 작업이 단일 작업으로 완료되는 단위입니다. 이는 원자성 쓰기의 단위이며 최적의 성능 및 안정성 특성을 갖기 위해 버퍼되지 않은 I/O를 정렬해야 합니다.
IOCTL_DISK_GET_DRIVE_GEOMETRY 및 GetDiskFreeSpace같은 대부분의 최신 Windows API는 논리적 섹터 크기를 반환하지만 실제 섹터 크기는 STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR 구조의 BytesPerPhysicalSector 멤버에 포함된 관련 정보와 함께 IOCTL_STORAGE_QUERY_PROPERTY 제어 코드를 통해 검색할 수 있습니다. 예제는 STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR샘플 코드를 참조하세요. Microsoft는 애플리케이션이 이 섹터 크기 전환에 대비할 수 있도록 IOCTL_STORAGE_QUERY_PROPERTY 제어 코드에서 보고한 대로 버퍼되지 않은 I/O를 실제 섹터 크기에 맞추는 것이 좋습니다.
Windows Server 2003 및 Windows XP:STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR 구조를 사용할 수 없습니다. Windows Vista 및 Windows Server 2008에서 도입되었습니다.
읽기 및 쓰기 작업에 대한 버퍼 주소는 섹터 정렬되어야 하므로 애플리케이션은 이러한 버퍼가 할당되는 방식을 직접 제어해야 합니다. 버퍼를 섹터 정렬하는 한 가지 방법은 VirtualAlloc 함수를 사용하여 버퍼를 할당하는 것입니다. 다음을 고려합니다.
- VirtualAlloc 시스템 페이지 크기의 정수 배수인 주소에 정렬된 메모리를 할당합니다. 페이지 크기는 x64의 경우 4,096바이트, Itanium 기반 시스템의 경우 x86 또는 8,192바이트입니다. 자세한 내용은 GetSystemInfo 함수를 참조하세요.
- 섹터 크기는 일반적으로 직접 액세스 스토리지 디바이스(하드 드라이브)의 경우 512~4,096바이트, CD-ROM의 경우 2,048바이트입니다.
- 페이지 및 섹터 크기는 모두 2의 힘입니다.
따라서 대부분의 경우 섹터 크기가 페이지 크기보다 큰 경우는 드물기 때문에 페이지 정렬 메모리도 섹터 정렬됩니다.
수동으로 정렬된 메모리 버퍼를 가져오는 또 다른 방법은 C Run-Time 라이브러리에서 _aligned_malloc 함수를 사용하는 것입니다. 버퍼 맞춤을 수동으로 제어하는 방법에 대한 예제는 WriteFile예제 코드 섹션의 C++ 언어 코드 예제를 참조하세요.