public class MemoryMap
{
[StructLayout(LayoutKind.Sequential)]
internal struct SYSTEM_INFO
{
public uint dwOemId;
public uint dwPageSize;
public uint lpMinimumApplicationAddress;
public uint lpMaximumApplicationAddress;
public uint dwActiveProcessorMask;
public uint dwNumberOfProcessors;
public uint dwProcessorType;
public uint dwAllocationGranularity;
public uint dwProcessorLevel;
public uint dwProcessorRevision;
}
private const uint GENERIC_READ = 0x80000000;
private const uint GENERIC_WRITE = 0x40000000;
private const int INVALID_HANDLE_VALUE = -1;
private const int FILE_ATTRIBUTE_NORMAL = 0x80;
private const uint FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;
private const uint PAGE_READWRITE = 0x04;
private const int FILE_MAP_COPY = 1;
private const int FILE_MAP_WRITE = 2;
private const int FILE_MAP_READ = 4;
/// <summary>
/// 内存映射文件句柄
/// </summary>
/// <param name="hFile"></param>
/// <param name="lpFileMappingAttributes"></param>
/// <param name="flProtect"></param>
/// <param name="dwMaximumSizeHigh"></param>
/// <param name="dwMaximumSizeLow"></param>
/// <param name="lpName"></param>
/// <returns></returns>
[DllImport("kernel32.dll")]
internal static extern IntPtr CreateFileMapping(IntPtr hFile, IntPtr lpFileMappingAttributes, uint flProtect, uint dwMaximumSizeHigh, uint dwMaximumSizeLow, string lpName);
/// <summary>
/// 内存映射文件
/// </summary>
/// <param name="hFileMappingObject"></param>
/// <param name="dwDesiredAccess"></param>
/// <param name="dwFileOffsetHigh"></param>
/// <param name="dwFileOffsetLow"></param>
/// <param name="dwNumberOfBytesToMap"></param>
/// <returns></returns>
[DllImport("kernel32.dll")]
internal static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, uint dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, uint dwNumberOfBytesToMap);
/// <summary>
/// 撤消文件映像
/// </summary>
/// <param name="lpBaseAddress"></param>
/// <returns></returns>
[DllImport("kernel32.dll")]
internal static extern bool UnmapViewOfFile(IntPtr lpBaseAddress);
/// <summary>
/// 关闭内核对象句柄
/// </summary>
/// <param name="hObject"></param>
/// <returns></returns>
[DllImport("kernel32.dll")]
internal static extern bool CloseHandle(IntPtr hObject);
/// <summary>
/// 打开要映射的文件
/// </summary>
/// <param name="lpFileName"></param>
/// <param name="dwDesiredAccess"></param>
/// <param name="dwShareMode"></param>
/// <param name="securityAttrs"></param>
/// <param name="dwCreationDisposition"></param>
/// <param name="dwFlagsAndAttributes"></param>
/// <param name="hTemplateFile"></param>
/// <returns></returns>
[DllImport("kernel32.dll")]
internal static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, FileShare dwShareMode, IntPtr securityAttrs, FileMode dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);
private uint m_MemSize = 20 * 1024 * 1024; //默认映射内存大小20M
/// <summary>
/// 使用内存文件映射得到文件内容
/// </summary>
/// <param name="path">文件路径</param>
/// <returns></returns>
public List<byte> GetFileContent(string path)
{
List<byte> bytes = new List<byte>();
IntPtr fileHandle = CreateFile(path, GENERIC_READ | GENERIC_WRITE, FileShare.Read | FileShare.Write, IntPtr.Zero, FileMode.Open, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, IntPtr.Zero);
if (INVALID_HANDLE_VALUE != (int)fileHandle)
{
IntPtr mappingFileHandle = CreateFileMapping(fileHandle, IntPtr.Zero, PAGE_READWRITE, 0, 0, $"~MappingTemp{Thread.CurrentThread.ManagedThreadId}");
if (mappingFileHandle != IntPtr.Zero)
{
System.IO.FileInfo f = new System.IO.FileInfo(path);
long fileSize = f.Length;
uint fileOffset = 0;
uint blockBytes = m_MemSize;
byte[] temp = new byte[blockBytes];
//分块读取内存,适用于几G的文件
while (fileSize > 0)
{
if (fileSize < blockBytes)
{
blockBytes = (uint)fileSize;
Array.Resize(ref temp, (int)blockBytes);
}
//映射视图,得到地址
IntPtr lpbMapAddress = MapViewOfFile(mappingFileHandle, FILE_MAP_COPY | FILE_MAP_READ | FILE_MAP_WRITE, GetHighWord((UInt64)fileOffset), GetLowWord((UInt64)fileOffset), blockBytes);
if (lpbMapAddress == IntPtr.Zero)
{
return bytes;
}
//对映射的视图进行访问,从非托管的内存中复制内容到托管的内存中
Marshal.Copy(lpbMapAddress, temp, 0, (int)blockBytes);
bytes.AddRange(temp);
//清空临时数组
Array.Clear(temp, 0, temp.Length);
//撤消文件映像
UnmapViewOfFile(lpbMapAddress);
//修正参数
fileOffset += blockBytes;
fileSize -= blockBytes;
}
CloseHandle(mappingFileHandle);
}
}
return bytes;
}
/// <summary>
/// 获取高32位
/// </summary>
/// <param name="intValue"></param>
/// <returns></returns>
private uint GetHighWord(UInt64 intValue)
{
return Convert.ToUInt32(intValue >> 32);
}
/// <summary>
/// 获取低32位
/// </summary>
/// <param name="intValue"></param>
/// <returns></returns>
private uint GetLowWord(UInt64 intValue)
{
return Convert.ToUInt32(intValue & 0x00000000FFFFFFFF);
}
}
C#使用内存映射方式读取二进制文件
最新推荐文章于 2023-06-15 19:41:19 发布