방법: Windows ReadFile 함수 사용(C# 프로그래밍 가이드)
업데이트: 2007년 11월
이 예제에서는 텍스트 파일을 읽고 표시하는 Windows ReadFile 함수를 보여 줍니다. ReadFile 함수에는 unsafe 코드를 사용해야 합니다. 이 함수에는 포인터를 매개 변수로 사용해야 하기 때문입니다.
Read 함수로 전달된 바이트 배열은 관리되는 형식입니다. 따라서 CLR(공용 언어 런타임) 가비지 수집기에서는 배열이 사용한 메모리를 임의대로 다시 할당할 수 있습니다. 이를 방지하려면 fixed를 사용하여 메모리에 대한 포인터를 가져오고 가비지 수집기가 이를 옮기지 못하도록 표시해야 합니다. fixed 블록의 끝에서 메모리가 자동으로 반환되어 가비지 수집을 통해 이동합니다.
이 기능을 선언적 고정이라고 합니다. 고정을 사용할 경우 fixed 블록에서 가비지 수집이 발생하는 매우 드문 경우 이외에는 오버헤드가 거의 없습니다. 하지만 고정으로 인해 전역 가비지 수집이 실행되는 동안 몇 가지 부작용이 나타날 수 있습니다. 예를 들어 가비지 수집기의 메모리 압축 기능은 고정된 버퍼 때문에 상당히 제한됩니다. 따라서 가능하면 고정을 사용하지 않는 것이 좋습니다.
예제
class FileReader
{
const uint GENERIC_READ = 0x80000000;
const uint OPEN_EXISTING = 3;
System.IntPtr handle;
[System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
static extern unsafe System.IntPtr CreateFile
(
string FileName, // file name
uint DesiredAccess, // access mode
uint ShareMode, // share mode
uint SecurityAttributes, // Security Attributes
uint CreationDisposition, // how to create
uint FlagsAndAttributes, // file attributes
int hTemplateFile // handle to template file
);
[System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)]
static extern unsafe bool ReadFile
(
System.IntPtr hFile, // handle to file
void* pBuffer, // data buffer
int NumberOfBytesToRead, // number of bytes to read
int* pNumberOfBytesRead, // number of bytes read
int Overlapped // overlapped buffer
);
[System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)]
static extern unsafe bool CloseHandle
(
System.IntPtr hObject // handle to object
);
public bool Open(string FileName)
{
// open the existing file for reading
handle = CreateFile
(
FileName,
GENERIC_READ,
0,
0,
OPEN_EXISTING,
0,
0
);
if (handle != System.IntPtr.Zero)
{
return true;
}
else
{
return false;
}
}
public unsafe int Read(byte[] buffer, int index, int count)
{
int n = 0;
fixed (byte* p = buffer)
{
if (!ReadFile(handle, p + index, count, &n, 0))
{
return 0;
}
}
return n;
}
public bool Close()
{
return CloseHandle(handle);
}
}
class Test
{
static int Main(string[] args)
{
if (args.Length != 1)
{
System.Console.WriteLine("Usage : ReadFile <FileName>");
return 1;
}
if (!System.IO.File.Exists(args[0]))
{
System.Console.WriteLine("File " + args[0] + " not found.");
return 1;
}
byte[] buffer = new byte[128];
FileReader fr = new FileReader();
if (fr.Open(args[0]))
{
// Assume that an ASCII file is being read.
System.Text.ASCIIEncoding Encoding = new System.Text.ASCIIEncoding();
int bytesRead;
do
{
bytesRead = fr.Read(buffer, 0, buffer.Length);
string content = Encoding.GetString(buffer, 0, bytesRead);
System.Console.Write("{0}", content);
}
while (bytesRead > 0);
fr.Close();
return 0;
}
else
{
System.Console.WriteLine("Failed to open requested file");
return 1;
}
}
}
참고 항목
개념
참조
안전하지 않은 코드 및 포인터(C# 프로그래밍 가이드)