-
[윈도우 시스템 프로그래밍] 압축 파일 복사하기개발/C·C++ 2024. 8. 27. 23:17
파일을 윈도우에서 제공하는 API를 통해 메모리로 추상화를 하면 파일을 메모리처럼 사용할 수 있다. 텍스트 파일을 메모리로 추상화하면 strcpy_s() 함수를 이용해 텍스트 파일에 문자열을 복사할 수 있으며 같은 맥락에서 파일 복사 역시 memcpy_s() 사용해서 편하게 복사할 수 있다.
기본 과정은 어렵지 않고 세부적으로 함수를 호출할 때 플래그만 잘 넣어주면 된다. 예를 들어 읽기 속성으로 파일 핸들을 구했는데, 매핑 객체를 만드는 함수를 호출할 때 읽기/쓰기 플래그를 넣으면 정상적인 반환 값을 얻을 수 없다. 테스트 파일은 압축 파일이다. 압축 파일은 crc로 무결성을 검사하기 때문에 정확한 복사 여부를 확인할 수 있기 때문이다. 복사한 압축 파일을 풀어서 데이터를 열람할 수 있으면 된다. 다음은 파일의 복사 과정이다.
1. 파일에 대한 핸들을 얻는다
2. 핸들을 통해 매핑 객체를 얻는다
3. 매핑 객체에 접근할 수 있는 포인터를 얻는다
4. 포인터로 필요한 연산을 수행한다(strcpy, memcpy)
5. 리소스를 해제한다(코드의 마지막 부분 확인)
- 파일 핸들을 얻은 뒤 매핑 객체에 접근할 수 있는 포인터를 얻는 부분까지를 함수화했다
- 이 과정에서 함수에 달리 넣어야 하는 플래그를 인수로 받는다
- 원본 파일에 대해 매핑 객체, 포인터를 구할 때는 읽기 연산만 필요하기 때문에 파일 사이즈는 0이어도 된다
- 복사 파일에 대해 매핑 객체, 포인터를 구할 때는 원본 파일의 크기를 지정해줘야 한다
#include <Windows.h> #include <cstdio> // 파일 핸들에 대한 접근 포인터 얻기 void* GetPointerFromFileHandle(HANDLE handle_file, DWORD file_protect, DWORD desired_access, DWORD file_size) { if (nullptr == handle_file) { printf("CreateFile() error: %d\n", GetLastError()); return nullptr; } // 파일에 대해 매핑 객체 만들기 HANDLE handle_map_file = CreateFileMapping( handle_file, nullptr, file_protect, 0, file_size, nullptr ); if (nullptr == handle_map_file) { wprintf(TEXT("CreateFileMapping() Error: %d"), GetLastError()); CloseHandle(handle_file); return nullptr; } // 매핑 객체에 대한 접근 포인터 얻기 void* result_ptr = MapViewOfFile( handle_map_file, desired_access, 0, 0, file_size ); if (nullptr == result_ptr) { wprintf(TEXT("MapViewOfFile() Error: %d"), GetLastError()); CloseHandle(handle_map_file); CloseHandle(handle_file); return nullptr; } CloseHandle(handle_map_file); return result_ptr; } // 파일 매핑을 이용해 파일 복사하기 int main() { // 파일 핸들 얻기 HANDLE handle_dest_file = CreateFile( TEXT("D:\\TEST\\test_2_copy.zip"), GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr ); if (nullptr == handle_dest_file) { printf("CreateFile() error: %d\n", GetLastError()); return 0; } HANDLE handle_source_file = CreateFile( TEXT("D:\\TEST\\test_2.zip"), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr ); LARGE_INTEGER file_size; if (!GetFileSizeEx(handle_source_file, &file_size)) { printf("GetFileSizeEx() failed with error %d\n", GetLastError()); CloseHandle(handle_dest_file); CloseHandle(handle_source_file); return 0; } // 복사할 파일에 대한 매핑 객체 생성 char* dest_map_ptr = (char*)GetPointerFromFileHandle(handle_dest_file, PAGE_READWRITE, FILE_MAP_ALL_ACCESS, file_size.QuadPart); // 원본 파일에 대한 매핑 객체 생성 char* source_map_ptr = (char*)GetPointerFromFileHandle(handle_source_file, PAGE_READONLY, FILE_MAP_READ, 0); if (nullptr == dest_map_ptr || nullptr == source_map_ptr) { CloseHandle(handle_dest_file); CloseHandle(handle_source_file); return 0; } memcpy_s(dest_map_ptr, file_size.QuadPart, source_map_ptr, file_size.QuadPart); UnmapViewOfFile(dest_map_ptr); UnmapViewOfFile(source_map_ptr); CloseHandle(handle_source_file); CloseHandle(handle_dest_file); }
'개발 > C·C++' 카테고리의 다른 글
포인터의 타입 추론 (0) 2024.08.31 [사소한 테스트] 곱셉/나머지 연산의 로직을 덧셈/뺄셈으로 변경한다면? (1) 2024.08.28 std::remove_if, std::erase (0) 2024.08.17 전화번호 무작위 생성 (0) 2024.08.03 [정렬] 더미 노드와 병합 정렬 (0) 2024.07.18