Windows 파일 캐시를 사용하지 않고 파일 복사하기
Windows 내에서 파일 관리와 관련하여, 운영 체제의 파일 캐시가 성능을 저하시킬 수 있는 상황을 마주칠 수 있습니다. 특히 대용량 파일을 처리할 때 더욱 그렇습니다. 예를 들어, USB 드라이브나 서버에서 로컬 머신으로 대용량 파일을 복사할 때 Windows가 파일을 캐시하기 때문에 데이터 스와핑이 발생하고 작업 완료까지 걸리는 시간이 늘어날 수 있습니다.
이번 블로그 포스트에서는 C#을 사용하여 Windows 파일 시스템 캐시를 사용하지 않고 파일을 복사하는 방법에 대해 알아보겠습니다.
Windows 파일 시스템 캐시 이해하기
코딩 솔루션으로 들어가기 전에 파일 시스템 캐시란 무엇인지 이해하는 것이 중요합니다. Windows는 파일 작업을 더 빠르게 할 수 있도록 캐시를 사용합니다. 이 과정은 보통 다음과 같은 방식으로 진행됩니다:
- 파일 데이터를 메모리에 저장하여 더 빠르게 접근할 수 있도록 합니다.
- USB 드라이브와 같은 느린 장치에서 데이터를 빠른 시스템 메모리로 오프로드하려 합니다.
하지만 2 GiB 이상의 대용량 파일의 경우, 시스템이 사용 가능한 메모리를 관리하려고 시도하기 때문에 이 캐시 과정이 비효율적일 수 있습니다.
솔루션: Win32 API 호출 사용하기
이 캐싱 동작을 우회하기 위해 Windows는 파일 작업을 수행할 때 사용할 수 있는 특정 플래그를 제공합니다. 이 플래그는 다음과 같습니다:
FILE_FLAG_WRITE_THROUGH
: 이 플래그는 파일에 대한 쓰기가 메모리에 캐시되지 않고 저장 장치에 직접 기록되도록 보장합니다.FILE_FLAG_NO_BUFFERING
: 이 플래그는 파일에 대한 시스템 캐시를 비활성화하여 모든 읽기 및 쓰기 작업이 캐시 없이 직접 디스크로 이동하게 합니다.
이 플래그들을 C# 코드에서 활용하여 캐시를 사용하지 않고 직접 파일 복사를 수행할 수 있습니다.
C#에서 단계별 구현하기
다음은 C#에서 솔루션을 구현하는 방법입니다:
-
필요한 라이브러리 추가: 파일 작업과 상호 운용성 서비스를 위한 필수 네임스페이스를 포함합니다.
using System; using System.IO; using System.Runtime.InteropServices;
-
네이티브 메서드 선언: 필요한 Win32 API 함수를 선언합니다.
[DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr CreateFile( string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile); [DllImport("kernel32.dll", SetLastError = true)] public static extern bool ReadFile( IntPtr hFile, byte[] lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped); [DllImport("kernel32.dll", SetLastError = true)] public static extern bool WriteFile( IntPtr hFile, byte[] lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped); [DllImport("kernel32.dll", SetLastError = true)] public static extern bool CloseHandle(IntPtr hObject);
-
플래그 사용: 파일 복사 함수에서 플래그를 사용하여 파일 핸들을 만듭니다.
public void CopyFileWithoutCache(string sourceFilePath, string destFilePath) { const uint GENERIC_READ = 0x80000000; const uint GENERIC_WRITE = 0x40000000; const uint OPEN_EXISTING = 3; const uint FILE_FLAG_WRITE_THROUGH = 0x80000000; const uint FILE_FLAG_NO_BUFFERING = 0x20000000; IntPtr sourceHandle = CreateFile(sourceFilePath, GENERIC_READ, 0, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, IntPtr.Zero); IntPtr destHandle = CreateFile(destFilePath, GENERIC_WRITE, 0, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, IntPtr.Zero); // 파일 읽기 및 쓰기 로직 구현하기... CloseHandle(sourceHandle); CloseHandle(destHandle); }
결론
위의 단계들을 통해 Windows 파일 시스템 캐시의 간섭 없이 대용량 파일을 효율적으로 복사할 수 있습니다. 이 방법은 USB 드라이브와 같은 느린 장치에서 전송된 대용량 파일을 처리할 때 특히 유용합니다.
더 자세한 내용은 Microsoft 문서에서 FILE_FLAG_WRITE_THROUGH 및 FILE_FLAG_NO_BUFFERING에 대해 확인하세요.
이 플래그들을 이해하고 활용함으로써 파일 작업의 성능을 크게 향상시킬 수 있습니다. 코딩 즐기세요!