인프런 커뮤니티 질문&답변

박경훈님의 프로필 이미지
박경훈

작성한 질문수

Windows 시스템 프로그래밍 - 기본

메모리 맵 파일강의 숙제 검사

해결된 질문

작성

·

204

·

수정됨

0

안녕하세요 선생님. 메모리 맵 파일강의 에서 내주신 숙제를 풀어 봤는데, 혹시 검사 부탁드려도 될까요?

아래의 코드가 제가 작성한 코드인데 혹시 잘못된 부분이나 고치면 좋겠다 하는 부분을 알려주시면 대단히 감사하겠습니다. 그리고 따로 질문 사항이 아래와 같이 있습니다.

  1. 메모리 맵 방식이 WriteFile() 방식보다 쓰기 속도가 더 빠를까요?

  2. chunkSize를 높여서 한번에 wirte하면 더 빠르다 강의에서 하셨는데, 어떠한 기준으로 메모리 효율이나 쓰기속도를 고려한 chunkSize의 최적의 사이즈를 구할수 있을까요?

항상 좋은 강의 만들어 주셔서 감사합니다!


#include <iostream>
#include <windows.h>

// Custom deleter for HANDLE
struct HandleDeleter {
	void operator()(HANDLE handle) {
		if (handle != INVALID_HANDLE_VALUE) {
			CloseHandle(handle);
		}
	}
};

typedef std::unique_ptr<std::remove_pointer<HANDLE>::type, HandleDeleter> UniqueHandle;

int main() {
	_wsetlocale(LC_ALL, L"korean");

	const wchar_t* sourceFilePath = L"C:\\TEST\\Sleep Away.zip";
	const wchar_t* targetFilePath = L"C:\\TEST\\Sleep Away - copy.zip";

	// Open source file
	UniqueHandle hFileSource{ CreateFile(sourceFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL) };
	if (hFileSource.get() == INVALID_HANDLE_VALUE) {
		wprintf(L"Failed to open source file [ERROR CODE: %d]\n", GetLastError());
		return 0;
	}

	// Open target file
	UniqueHandle hFileTarget{ CreateFile(targetFilePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL) };
	if (hFileTarget.get() == INVALID_HANDLE_VALUE) {
		wprintf(L"Failed to open target file [ERROR CODE: %d]\n", GetLastError());
		return 0;
	}

	// Set the size of the target file to match the source file
	LARGE_INTEGER fileSize;
	GetFileSizeEx(hFileSource.get(), &fileSize);
	if (!SetFilePointerEx(hFileTarget.get(), fileSize, nullptr, FILE_BEGIN) || !SetEndOfFile(hFileTarget.get())) {
		wprintf(L"Failed to set size of target file [ERROR CODE: %d]\n", GetLastError());
		return 0;
	}

	// Create file mappings
	UniqueHandle hMapSource{ CreateFileMapping(hFileSource.get(), NULL, PAGE_READONLY, 0, 0, NULL) };
	UniqueHandle hMapTarget{ CreateFileMapping(hFileTarget.get(), NULL, PAGE_READWRITE, 0, 0, NULL) };
	if (hMapSource.get() == nullptr || hMapTarget.get() == nullptr) {
		wprintf(L"Failed to create file mappings [ERROR CODE: %d]\n", GetLastError());
		return 0;
	}

	// Constants for the operation
	const DWORD chunkSize = 65536; // 64 KB
	DWORD bytesCopied = 0;

	for (LONGLONG offset = 0; offset < fileSize.QuadPart; offset += chunkSize) {
		DWORD size = static_cast<DWORD>(min(static_cast<LONGLONG>(chunkSize), fileSize.QuadPart - offset));

		// Map a chunk from the source file
		auto pSrc = static_cast<char*>(MapViewOfFile(hMapSource.get(), FILE_MAP_READ, 0, offset, size));
		if (pSrc == nullptr) {
			wprintf(L"Failed to map view of source file [ERROR CODE: %d]\n", GetLastError());
			break;
		}

		// Map a chunk to the target file
		auto pDst = static_cast<char*>(MapViewOfFile(hMapTarget.get(), FILE_MAP_WRITE, 0, offset, size));
		if (pDst == nullptr) {
			wprintf(L"Failed to map view of target file [ERROR CODE: %d]\n", GetLastError());
			UnmapViewOfFile(pSrc);
			break;
		}

		// Copy the chunk
		memcpy(pDst, pSrc, size);
		bytesCopied += size;
		wprintf(L"%I64d%%\n", offset * 100 / fileSize.QuadPart);

		// Unmap the chunks
		UnmapViewOfFile(pSrc);
		UnmapViewOfFile(pDst);
	}

	wprintf(L"Copy complete! The original file size is %lld bytes and %d bytes copied.\n", fileSize.QuadPart, bytesCopied);

	return 0;
}

답변 1

0

널널한 개발자님의 프로필 이미지
널널한 개발자
지식공유자

for loop를 사용할 이유가 없습니다. 원본 파일에 대한 크기를 알아내 대상 파일의 크기를 강제로 조정했다면 두 파일의 크기는 같습니다. 이 상태에서 메모리로 추상화 했기 때문에 메모리 카피는 한 번만 해도 됩니다. 참고하시기 바랍니다. :)

박경훈님의 프로필 이미지
박경훈

작성한 질문수

질문하기