内存映射

读取文件时不可避免的与到大数据的读取,100M,200M...以至于1G,2G

那么这个时候直接用文本或二进制读取,是读不来的,内存空间都没有这么大,比如在桌面打开一个1G的txt文档

这会直接崩掉的。

这里就出现了一种比较复杂的读取方式,内存映射(当然也可以读取数据时一行一行的读取数据,读一行数据就往数据库中添加)

内存映射文件是磁盘文件的全部或部分内容与虚拟地址空间的某个区域建立关联,可以对被映射的文件进行直接访问,而不必执行文件I/O操作也无需对文件内容进行缓存处理.

 下面就是c#使用内存映射文件方式读取文件的代码.

[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 OPEN_EXISTING = 3;
        private const int INVALID_HANDLE_VALUE = -1;
        private const int FILE_FLAG_NO_BUFFERING = 0x20000000;
        private const int FILE_ATTRIBUTE_NORMAL = 0x80;
        private const uint FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;
        private const uint PAGE_READWRITE = 0x04;
        private const uint PAGE_READONLY = 0x02;

        private const int FILE_MAP_COPY = 1;
        private const int FILE_MAP_WRITE = 2;
        private const int FILE_MAP_READ = 4;


        // 内存映射文件句柄
        [DllImport("kernel32.dll")]
        internal static extern IntPtr CreateFileMapping(IntPtr hFile,
            IntPtr lpFileMappingAttributes, uint flProtect,
            uint dwMaximumSizeHigh,
            uint dwMaximumSizeLow, string lpName);

        // 内存映射文件
        [DllImport("kernel32.dll")]
        internal static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, uint
            dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow,
            uint dwNumberOfBytesToMap);

        // 撤消文件映像
        [DllImport("kernel32.dll")]
        internal static extern bool UnmapViewOfFile(IntPtr lpBaseAddress);

        // 关闭内核对象句柄
        [DllImport("kernel32.dll")]
        internal static extern bool CloseHandle(IntPtr hObject);

        // 打开要映射的文件
        [DllImport("kernel32.dll")]
        internal static extern IntPtr CreateFile(string lpFileName,
            uint dwDesiredAccess, FileShare dwShareMode, IntPtr securityAttrs,
            FileMode dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);

        // 得到文件大小
        [DllImport("kernel32.dll", SetLastError = true)]
        internal static extern uint GetFileSize(IntPtr hFile, out uint highSize);

        //得到系统信息
        [DllImport("kernel32.dll", SetLastError = true)]
        internal static extern void GetSystemInfo(ref SYSTEM_INFO lpSystemInfo);

        public bool ReadBigFile(string strBigFile)
        {
            //创建/打开一个文件内核对象
            IntPtr fileHandle = CreateFile(strBigFile,
           GENERIC_READ, FileShare.Read,
           IntPtr.Zero, FileMode.Open,
           FILE_FLAG_NO_BUFFERING, IntPtr.Zero);

            if (INVALID_HANDLE_VALUE != (int)fileHandle)
            {
                //创建一个文件映射内核对象
                IntPtr mappingFileHandle = CreateFileMapping(
                    fileHandle, IntPtr.Zero, PAGE_READONLY, 0, 0, "~MappingTemp");
                if (mappingFileHandle != IntPtr.Zero)
                {
                    SYSTEM_INFO systemInfo = new SYSTEM_INFO(); ;
                    GetSystemInfo(ref systemInfo);
                    //得到系统页分配粒度
                    uint allocationGranularity = systemInfo.dwAllocationGranularity;
                    uint fileSizeHigh = 0;
                    uint fileSize = GetFileSize(fileHandle, out fileSizeHigh);
                    fileSize |= (((uint)fileSizeHigh) << 32);
                    //关闭文件句柄 
                    CloseHandle(fileHandle);
                    uint fileOffset = 0;
                    uint blockBytes = 1000 * allocationGranularity;
                    if (fileSize < 1000 * allocationGranularity)
                        blockBytes = fileSize;

                    //分块读取内存
                    while (fileSize > 0)
                    {
                        if (fileSize < 1000 * allocationGranularity)
                            blockBytes = fileSize;
                        // 映射视图,得到地址 
                        IntPtr lpbMapAddress = MapViewOfFile(mappingFileHandle, FILE_MAP_READ,
                           0, (uint)(fileOffset & 0xFFFFFFFF),
                           blockBytes);

                        if (lpbMapAddress == IntPtr.Zero)
                        {
                            return false;
                        }
                        // 对映射的视图进行访问
                        byte[] temp = new byte[blockBytes];
                        //从非托管的内存中复制内容到托管的内存中
                        Marshal.Copy(lpbMapAddress, temp, 0, (int)blockBytes);

                        //---------do something----------------------

                        // 撤消文件映像
                        UnmapViewOfFile(lpbMapAddress);
                        // 修正参数
                        fileOffset += blockBytes;
                        fileSize -= blockBytes;
                    }
                    //关闭文件映射
                    CloseHandle(mappingFileHandle);
                }

            }
            return true;
        }
原文地址:https://www.cnblogs.com/bit-by-bit/p/4046157.html