ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [윈도우 시스템 프로그래밍] 압축 파일 복사하기
    개발/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);
    }

    댓글

Designed by Tistory.