zoukankan      html  css  js  c++  java
  • 内存映射

    读取文件时不可避免的与到大数据的读取,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;
            }
  • 相关阅读:
    IOS客户端Coding项目记录(二)
    IOS客户端Coding项目记录(一)
    IOS开发基础知识--碎片7
    图解域域树域林根域的含义
    Windows server 2012公用网络修改为专用网络
    Windows2012R2版本区别
    VMWare:vSphere6 企业版参考序列号
    Oracle快速测试连接是否成功
    Brocade300 commands
    也谈免拆机破解中兴B860av1.1(解决不能安装软件/解决遥控)
  • 原文地址:https://www.cnblogs.com/bit-by-bit/p/4046157.html
Copyright © 2011-2022 走看看