如何分块导入大位图(1G多)

时间:2021-09-20 14:41:00
如何分块导入大位图,图像大小为1.2G左右,有什么类可以用吗?还是用API函数?该怎么做呢?对其进行处理还得新建一个位图以存放处理完后的数据吧?谁有现成的代码吗?谢谢。。。

24 个解决方案

#1


经过试验,读取大文件时,分配内存失败,我查了一些资料,大文件操作时的内存分配都是分块进行,看来你需要自己进行内存分配管理了,大概思路就是读一块数据,分配一段内存,进行处理,然后显示到屏幕上,然后释放内存,继续读取下一块,再分配、再释放。至于分块读取位图的问题,这个就要看你想怎么分了,是按照行来分,还是按照块来分。大概思路就是分配一段内存lpDIB,再定义一个临时内存块lpTDIB,用来寻找目的块,用readhuge一段一段的读给lpTDIB,到了想要的段,就用memcpy拷贝给lpDIB,最后你想要的lpDIB就出来了。至于位图文件数据的存储格式和DIB图像数据存储格式是一样的,都是按照从左到右,从下到上的顺序存储像素数据的,注意黑白图像一个像素是1个机器位,也就是1个字节代表8个像素。另外需要注意的是,略过位图头文件后,不是读取到DIB头信息吗?这里的DIB头信息中的图像宽度、高度需要根据你所分的块进行修改,要是想把黑白图像转成8位图,那么DIB头信息还需要更改biBitCount、biClrUsed、biSizeImage的信息,调色板不能用原来的,需要自己加,就是从0,0,0,0 1,1,1,0 一直添加到255,255,255,0,最后像素数据也要从1位表示,改成8位表示,我在百度上刚发完。

#2


我尝试了分块导入图像,其中图像是灰度的,大小为1.2G,以下是我分块读入的部分代码,为什么第一个块分配内存可以成功,第二个开始就出错了呢?
//获取像素数据的大小(文件总长度-位图文件头的长度-位图信息的长度)
 DWORD dwSize=dwFileLength-sizeof(BITMAPFILEHEADER)-sizeof(BITMAPINFO);

 //Read the image by stocks
  lWidth=bitmapinfo.bmiHeader.biWidth;
  nBitCount=bitmapinfo.bmiHeader.biBitCount;
 LONG lLineByte=WIDTHBYTE(lWidth*nBitCount);


 DWORD dwSize1=lLineByte*10000;
 m_hDIB1=(HGLOBAL)::GlobalAlloc(GMEM_MOVEABLE,dwSize1);
  BYTE* m_pdib1=(BYTE*)::GlobalLock((HGLOBAL)m_hDIB1);
 DWORD dwReadSize1=dibFile.Read((void*)m_pdib1,dwSize1);

  DWORD dwSize2=lLineByte*10000;
 m_hDIB2=(HGLOBAL)::GlobalAlloc(GMEM_MOVEABLE,dwSize2);
  BYTE* m_pdib2=(BYTE*)::GlobalLock((HGLOBAL)m_hDIB2);
 DWORD dwReadSize2=dibFile.Read((void*)m_pdib2,dwSize2);

  DWORD dwSize3=lLineByte*10000;
 m_hDIB3=(HGLOBAL)::GlobalAlloc(GMEM_MOVEABLE,dwSize3);
  BYTE* m_pdib3=(BYTE*)::GlobalLock((HGLOBAL)m_hDIB3);
 DWORD dwReadSize3=dibFile.Read((void*)m_pdib3,dwSize3);

  DWORD dwSize4=dwSize-lLineByte*30000;
 m_hDIB4=(HGLOBAL)::GlobalAlloc(GMEM_MOVEABLE,dwSize4);
  BYTE* m_pdib4=(BYTE*)::GlobalLock((HGLOBAL)m_hDIB4);
 DWORD dwReadSize4=dibFile.Read((void*)m_pdib4,dwSize4);

#3


我一猜你就会这样顺序分块读取文件,这样肯定会出问题的。
首先,我需要知道你用什么方法实现图像在DC上的显示,反正不管什么方法,最后肯定用到windows API位图显示函数,以及位图句柄CBitmap m_hDIB1 ,以及位图指针CBitmap *m_pdib1,按照你的理解,把位图分块就是把文件按照大小分割,才得到m_pdib1,m_pdib2,m_pdib3,m_pdib4。但其实呢?除了第一个m_pdib1,其他的你得到的仅仅是一堆像素数据,并没有包含bitmapinfo信息,windows API位图显示函数不可能识别出来的。
因此,图像分割不是说像你想象的那样把图像数据分成几份就可以的,还需要分别给他们加上bitmapinfo,使他们分别成为一个独立的完整位图。另外单单把原有的bitmapinfo头拿来直接用,也是不行的,一看你就没好好看我的回答。我再次强调下
这里的DIB头信息中的图像宽度、高度需要根据你所分的块进行修改,
再次强调:黑白位图(就是单色图)和灰度图(大部分教材提到的都是指256色,8位图)是两回事,存储方式都不一样,别搞混了。
要是想把黑白图像转成8位图,那么DIB头信息还需要更改biBitCount、biClrUsed、biSizeImage的信息,调色板不能用原来的,需要自己加,就是从0,0,0,0 1,1,1,0 一直添加到255,255,255,0,最后像素数据也要从1位表示,改成8位表示

#4


非常感谢你啊,我才刚开始学图像处理呢,很多都还不懂呢。。。我会去仔细研究你说的话的。。。谢谢。。。如果我不将图像显示出来呢,我只是对灰度图像(1.2G)进行二值化、细化,那样的话我可以像我原来那样分块读入并处理吗?理论上1.2G的图像是可以读入内存的吗?

#5


对于大文件的处理,不要全部读入内存,直接用内存映射文件就可以了
CreateFileMapping
MapViewOfFile

#6


处理这么大的数据,用一般的PC能处理过来吗?要用大型计算机吧

#7


额 你这个问题我刚处理过,其实你可以打开文件,用文件指针操作文件里面的数据,1.2G就算文件映射完了,你也得读到缓存,但是没那么大的缓存,就算分段申请,也相对麻烦些,不如打开文件,分开读文件头信息头,然后接着移动文件指针,对数据内容进行一步步处理。我当初是这么实现的,也是处理1.2G的位图。不过有一缺陷,就是1.2G的文件在你打开瞬间还不能立即读,因为机子稍微不好的话,会导致程序崩溃,因为文件在打开瞬间,太大了,,没反应过来你就去读了肯定报错,因此我在这稍微Sleep了几秒钟,不过机子好的话几乎不存在这样的问题。希望可以帮到你。

#8


同意7楼的话,如果不为了显示的话,确实没有必要把文件数据读取到内存中,应该对文件指针进行操作,更直接一些。

#9


我前几天发过这个问题的帖子,你可以看一下http://topic.csdn.net/u/20110905/10/d1de46d7-67ab-4fda-9abd-b0e76971394d.html?31861。

#10


引用 7 楼 ankeysun 的回复:
额 你这个问题我刚处理过,其实你可以打开文件,用文件指针操作文件里面的数据,1.2G就算文件映射完了,你也得读到缓存,但是没那么大的缓存,就算分段申请,也相对麻烦些,不如打开文件,分开读文件头信息头,然后接着移动文件指针,对数据内容进行一步步处理。我当初是这么实现的,也是处理1.2G的位图。不过有一缺陷,就是1.2G的文件在你打开瞬间还不能立即读,因为机子稍微不好的话,会导致程序崩溃,因为文件在打……
非常感谢,你可以把你上次处理的代码给我看看吗?我的邮箱:472818342@qq.com我对文件指针不了解呢,你的话给了我很大帮助,我自己再研究研究啊。

#11


如果我每次只读入一个数据,但细化的时候需要周边像素数据,那样的话我还是需要读入一个分块吧?

#12


根据5楼的提示,采用CreateFileMapping、MapViewOfFile文件映射的方式做,还是这个办法好,直观、省事,不过比较考验机器的性能,我用了一下午时间,研究了一下,下面给出代码,你自己参考。
// 创建文件内核对象,其句柄保存于hFile 
HANDLE hFile = CreateFile(
lpszPathName,
GENERIC_WRITE|GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING, //注意这里是打开现有的CREATE_ALWAYS新建
FILE_FLAG_SEQUENTIAL_SCAN, 
NULL); 
DWORD dwFileSize;
        // 得到文件的大小
dwFileSize = GetFileSize(hFile,NULL);
// 创建文件映射内核对象,句柄保存于hFileMapping
HANDLE hFileMapping = CreateFileMapping(hFile,
NULL,
PAGE_READWRITE,
0,//(DWORD)(dwBitsSize >> 32), //因为我的文件不可能超过4G,所以我就没有采用__int64类型,
          //而是DWORD类,如果超过4G,请把dwBitsSize定义为__int64,然后采用注释掉的语句就可以了
dwFileSize,//(DWORD)(dwBitsSize & 0xFFFFFFFF),
NULL); 
// 释放文件内核对象
CloseHandle(hFile); 
// 设定大小、偏移量等参数 __int64是long long类型64位整数
__int64 qwFileOffset = 0;
// 将文件数据映射到进程的地址空间 
PBYTE pbFile = (PBYTE)MapViewOfFile(
hFileMapping,FILE_MAP_ALL_ACCESS,
(DWORD)(qwFileOffset>>32), 
(DWORD)(qwFileOffset&0xFFFFFFFF), 
dwFileSize);
BITMAPFILEHEADER bmfHeader; //bmp文件头结构
BITMAPINFO lpDIBHdr; //DIB头结构
PBYTE    lpDIBBits;  //DIB像素数据首地址
//获取bmp文件头数据
memcpy(&bmfHeader,pbFile,sizeof(bmfHeader));
//获取DIB头信息
memcpy(&lpDIBHdr,pbFile+sizeof(bmfHeader), *(pbFile+sizeof(bmfHeader)));
//获得DIB像素首地址
lpDIBBits = pbFile + sizeof(bmfHeader) + *(pbFile+sizeof(bmfHeader));
// 从进程的地址空间撤消文件数据映像
UnmapViewOfFile(pbFile);
// 关闭文件映射对象
CloseHandle(hFileMapping); 
经过验证完全没有问题,你要知道,大部分高手都比较懒,因为他们已经回答过好多遍了,所以都懒得回答太详细的内容,许多时候往往只是提点一句两句,给你提供一个方向,然后就需要你自己去研究,只有这样得来的东西才是自己的,否则拿来就用,往往学的似是而非,学习程序一定要有研究精神,我喜欢回答详细一点是因为我也是初学者,我学C++还不到3个月,学习图像处理也才2个月,只有在回答问题的过程中,才能发现自己没有理解到的地方。

#13


内存映射的话,多大的文件都没问题。当然每次读入多少到内存,取决于你的内存大小。还有就是,你准备如何处理数据,内存映射读入局部到内存,只是文本搜索,很好办,但要是排序,就无能为力了。所以取决于你图像处理如何进行。

如果真要一次性读入1.2G到内存,你就用window sever 2003 64bit或者Win 7做操作系统。

#14


引用 12 楼 zhufeng1001 的回复:
根据5楼的提示,采用CreateFileMapping、MapViewOfFile文件映射的方式做,还是这个办法好,直观、省事,不过比较考验机器的性能,我用了一下午时间,研究了一下,下面给出代码,你自己参考。
// 创建文件内核对象,其句柄保存于hFile 
HANDLE hFile = CreateFile(
lpszPathName,
GENERIC_WRITE|GENERIC_REA……
非常感谢啊。你不仅授之以鱼,还授之以渔。。。我会研究的。。。

#15


如果1.2g只是图像数据,不含文件头信息,可以使用createdibsection,其中hSection参数为数据文件的映射句柄,用CreateFileMapping创建的,还有个参数是设置数据文件的偏移量,以字节为单位,这个好处是可以将图片分块映射成为dib,不占用大量虚拟内存,我试用这种方法显示1.6g图像的,dib是1024*1024像素块.

#16


引用 15 楼 njsf_79 的回复:
如果1.2g只是图像数据,不含文件头信息,可以使用createdibsection,其中hSection参数为数据文件的映射句柄,用CreateFileMapping创建的,还有个参数是设置数据文件的偏移量,以字节为单位,这个好处是可以将图片分块映射成为dib,不占用大量虚拟内存,我试用这种方法显示1.6g图像的,dib是1024*1024像素块.

又学习了,我还在想呢,能计算出图像数据的地址,怎么得到DIB图像的句柄呢,15楼就给出了函数,知识还在于积累和交流。
createdibsection()函数
HBITMAP CreateDIBSection(HDC hdc,CONST BITMAPINFO *pbmi,UINT iUsage,VOID** ppvBits,HANDLE hSection,DWORD dwOffset); 
如果函数执行成功,那么返回值是一个指向刚刚创建的与设备无关位图的句柄,并且*ppvBits指向该位图的位数据值;如果函数执行失败,那么返回值为NULL,并且*ppvBit也为NULL

#17


引用 12 楼 zhufeng1001 的回复:
根据5楼的提示,采用CreateFileMapping、MapViewOfFile文件映射的方式做,还是这个办法好,直观、省事,不过比较考验机器的性能,我用了一下午时间,研究了一下,下面给出代码,你自己参考。
// 创建文件内核对象,其句柄保存于hFile 
HANDLE hFile = CreateFile(
lpszPathName,
GENERIC_WRITE|GENERIC_REA……
我尝试了这段代码,在运行时会在这一步出错://获取bmp文件头数据
memcpy(&bmfHeader,pbFile,sizeof(bmfHeader));
提示读取位置时发生访问冲突。这是为什么?

#18


是否是因为&bmfHeader尚未创建?

#19


引用 12 楼 zhufeng1001 的回复:
根据5楼的提示,采用CreateFileMapping、MapViewOfFile文件映射的方式做,还是这个办法好,直观、省事,不过比较考验机器的性能,我用了一下午时间,研究了一下,下面给出代码,你自己参考。
// 创建文件内核对象,其句柄保存于hFile 
HANDLE hFile = CreateFile(
lpszPathName,
GENERIC_WRITE|GENERIC_REA……
经测试,用这方法可以顺利读取560MB的图片,但读入1.2G图像时会出错,即在memcpy处出错,这是为什么?是因为文件太大,空间不够?

#20


你倒是把你用的memcpy的代码贴出来啊
你不贴怎么知道哪里错了,再说根据我的用法的话
//获取bmp文件头数据
memcpy(&bmfHeader,pbFile,sizeof(bmfHeader));
//获取DIB头信息
memcpy(&lpDIBHdr,pbFile+sizeof(bmfHeader), *(pbFile+sizeof(bmfHeader)));
//获得DIB像素首地址
lpDIBBits = pbFile + sizeof(bmfHeader) + *(pbFile+sizeof(bmfHeader));
sizeof(bmfHeader)和*(pbFile+sizeof(bmfHeader))应该都不大,也就几十字节
lpDIBBits只是一个地址,不涉及大小问题。
要出错也可能是*(pbFile+sizeof(bmfHeader))这个地址的值有问题。
有问题自己追踪把,很可能机器运行的过程和你想象的不一样,调试程序也是非常重要的一步。

#21


引用 20 楼 zhufeng1001 的回复:
你倒是把你用的memcpy的代码贴出来啊
你不贴怎么知道哪里错了,再说根据我的用法的话
//获取bmp文件头数据
memcpy(&bmfHeader,pbFile,sizeof(bmfHeader));
//获取DIB头信息
memcpy(&lpDIBHdr,pbFile+sizeof(bmfHeader), *(pbFile+sizeof(bmfHeader)));
……
//获取bmp文件头数据
memcpy(&bmfHeader,pbFile,sizeof(bmfHeader));
追踪到memcpy.asm中,调试指针指向:UnwindUp3:
        mov     eax,[esi+ecx*4-12] ;U(entry)/V(not) - get dword from source
                                   ;V(entry) - spare
        mov     [edi+ecx*4-12],eax ;U - put dword into destination
我在导入560MB图像都没问题,但到了1G就出错了,我真的搞不懂呢。

#22


追踪到memcpy.asm中,调试指针指向:UnwindUp3:
你追踪这个毫无意义,你只需要查看出错时,sizeof(bmfHeader),pbFile,&bmfHeader这些数据的值就好了
你可以依次察看*(pbFile),*(pbFile+1),*(pbFile+2),。。。。,*(pbFile+sizeof(bmfHeader)-1)的值啊
看看是不是符合你预期的数值,sizeof(bmfHeader)不大,而且是个固定植。
memcpy抱错只可能是你的pbfile当前指针指向有问题,另外如果pbFile是空也会出问题的,加条语句判断一下吧

#23


引用 22 楼 zhufeng1001 的回复:
追踪到memcpy.asm中,调试指针指向:UnwindUp3:
你追踪这个毫无意义,你只需要查看出错时,sizeof(bmfHeader),pbFile,&bmfHeader这些数据的值就好了
你可以依次察看*(pbFile),*(pbFile+1),*(pbFile+2),。。。。,*(pbFile+sizeof(bmfHeader)-1)的值啊
看看是不是符合你预期的数值,si……
我刚断点追踪了,发现是pbFile是错误的指针,这是什么原因呢?是在将文件数据映射到进程的地址空间时出错?是否跟文件的大小和计算机内存有关吗?急求

#24


引用 7 楼 ankeysun 的回复:
额 你这个问题我刚处理过,其实你可以打开文件,用文件指针操作文件里面的数据,1.2G就算文件映射完了,你也得读到缓存,但是没那么大的缓存,就算分段申请,也相对麻烦些,不如打开文件,分开读文件头信息头,然后接着移动文件指针,对数据内容进行一步步处理。我当初是这么实现的,也是处理1.2G的位图。不过有一缺陷,就是1.2G的文件在你打开瞬间还不能立即读,因为机子稍微不好的话,会导致程序崩溃,因为文件在打……


这个方法很好 用文件映射好些,可以处理大的文件

#1


经过试验,读取大文件时,分配内存失败,我查了一些资料,大文件操作时的内存分配都是分块进行,看来你需要自己进行内存分配管理了,大概思路就是读一块数据,分配一段内存,进行处理,然后显示到屏幕上,然后释放内存,继续读取下一块,再分配、再释放。至于分块读取位图的问题,这个就要看你想怎么分了,是按照行来分,还是按照块来分。大概思路就是分配一段内存lpDIB,再定义一个临时内存块lpTDIB,用来寻找目的块,用readhuge一段一段的读给lpTDIB,到了想要的段,就用memcpy拷贝给lpDIB,最后你想要的lpDIB就出来了。至于位图文件数据的存储格式和DIB图像数据存储格式是一样的,都是按照从左到右,从下到上的顺序存储像素数据的,注意黑白图像一个像素是1个机器位,也就是1个字节代表8个像素。另外需要注意的是,略过位图头文件后,不是读取到DIB头信息吗?这里的DIB头信息中的图像宽度、高度需要根据你所分的块进行修改,要是想把黑白图像转成8位图,那么DIB头信息还需要更改biBitCount、biClrUsed、biSizeImage的信息,调色板不能用原来的,需要自己加,就是从0,0,0,0 1,1,1,0 一直添加到255,255,255,0,最后像素数据也要从1位表示,改成8位表示,我在百度上刚发完。

#2


我尝试了分块导入图像,其中图像是灰度的,大小为1.2G,以下是我分块读入的部分代码,为什么第一个块分配内存可以成功,第二个开始就出错了呢?
//获取像素数据的大小(文件总长度-位图文件头的长度-位图信息的长度)
 DWORD dwSize=dwFileLength-sizeof(BITMAPFILEHEADER)-sizeof(BITMAPINFO);

 //Read the image by stocks
  lWidth=bitmapinfo.bmiHeader.biWidth;
  nBitCount=bitmapinfo.bmiHeader.biBitCount;
 LONG lLineByte=WIDTHBYTE(lWidth*nBitCount);


 DWORD dwSize1=lLineByte*10000;
 m_hDIB1=(HGLOBAL)::GlobalAlloc(GMEM_MOVEABLE,dwSize1);
  BYTE* m_pdib1=(BYTE*)::GlobalLock((HGLOBAL)m_hDIB1);
 DWORD dwReadSize1=dibFile.Read((void*)m_pdib1,dwSize1);

  DWORD dwSize2=lLineByte*10000;
 m_hDIB2=(HGLOBAL)::GlobalAlloc(GMEM_MOVEABLE,dwSize2);
  BYTE* m_pdib2=(BYTE*)::GlobalLock((HGLOBAL)m_hDIB2);
 DWORD dwReadSize2=dibFile.Read((void*)m_pdib2,dwSize2);

  DWORD dwSize3=lLineByte*10000;
 m_hDIB3=(HGLOBAL)::GlobalAlloc(GMEM_MOVEABLE,dwSize3);
  BYTE* m_pdib3=(BYTE*)::GlobalLock((HGLOBAL)m_hDIB3);
 DWORD dwReadSize3=dibFile.Read((void*)m_pdib3,dwSize3);

  DWORD dwSize4=dwSize-lLineByte*30000;
 m_hDIB4=(HGLOBAL)::GlobalAlloc(GMEM_MOVEABLE,dwSize4);
  BYTE* m_pdib4=(BYTE*)::GlobalLock((HGLOBAL)m_hDIB4);
 DWORD dwReadSize4=dibFile.Read((void*)m_pdib4,dwSize4);

#3


我一猜你就会这样顺序分块读取文件,这样肯定会出问题的。
首先,我需要知道你用什么方法实现图像在DC上的显示,反正不管什么方法,最后肯定用到windows API位图显示函数,以及位图句柄CBitmap m_hDIB1 ,以及位图指针CBitmap *m_pdib1,按照你的理解,把位图分块就是把文件按照大小分割,才得到m_pdib1,m_pdib2,m_pdib3,m_pdib4。但其实呢?除了第一个m_pdib1,其他的你得到的仅仅是一堆像素数据,并没有包含bitmapinfo信息,windows API位图显示函数不可能识别出来的。
因此,图像分割不是说像你想象的那样把图像数据分成几份就可以的,还需要分别给他们加上bitmapinfo,使他们分别成为一个独立的完整位图。另外单单把原有的bitmapinfo头拿来直接用,也是不行的,一看你就没好好看我的回答。我再次强调下
这里的DIB头信息中的图像宽度、高度需要根据你所分的块进行修改,
再次强调:黑白位图(就是单色图)和灰度图(大部分教材提到的都是指256色,8位图)是两回事,存储方式都不一样,别搞混了。
要是想把黑白图像转成8位图,那么DIB头信息还需要更改biBitCount、biClrUsed、biSizeImage的信息,调色板不能用原来的,需要自己加,就是从0,0,0,0 1,1,1,0 一直添加到255,255,255,0,最后像素数据也要从1位表示,改成8位表示

#4


非常感谢你啊,我才刚开始学图像处理呢,很多都还不懂呢。。。我会去仔细研究你说的话的。。。谢谢。。。如果我不将图像显示出来呢,我只是对灰度图像(1.2G)进行二值化、细化,那样的话我可以像我原来那样分块读入并处理吗?理论上1.2G的图像是可以读入内存的吗?

#5


对于大文件的处理,不要全部读入内存,直接用内存映射文件就可以了
CreateFileMapping
MapViewOfFile

#6


处理这么大的数据,用一般的PC能处理过来吗?要用大型计算机吧

#7


额 你这个问题我刚处理过,其实你可以打开文件,用文件指针操作文件里面的数据,1.2G就算文件映射完了,你也得读到缓存,但是没那么大的缓存,就算分段申请,也相对麻烦些,不如打开文件,分开读文件头信息头,然后接着移动文件指针,对数据内容进行一步步处理。我当初是这么实现的,也是处理1.2G的位图。不过有一缺陷,就是1.2G的文件在你打开瞬间还不能立即读,因为机子稍微不好的话,会导致程序崩溃,因为文件在打开瞬间,太大了,,没反应过来你就去读了肯定报错,因此我在这稍微Sleep了几秒钟,不过机子好的话几乎不存在这样的问题。希望可以帮到你。

#8


同意7楼的话,如果不为了显示的话,确实没有必要把文件数据读取到内存中,应该对文件指针进行操作,更直接一些。

#9


我前几天发过这个问题的帖子,你可以看一下http://topic.csdn.net/u/20110905/10/d1de46d7-67ab-4fda-9abd-b0e76971394d.html?31861。

#10


引用 7 楼 ankeysun 的回复:
额 你这个问题我刚处理过,其实你可以打开文件,用文件指针操作文件里面的数据,1.2G就算文件映射完了,你也得读到缓存,但是没那么大的缓存,就算分段申请,也相对麻烦些,不如打开文件,分开读文件头信息头,然后接着移动文件指针,对数据内容进行一步步处理。我当初是这么实现的,也是处理1.2G的位图。不过有一缺陷,就是1.2G的文件在你打开瞬间还不能立即读,因为机子稍微不好的话,会导致程序崩溃,因为文件在打……
非常感谢,你可以把你上次处理的代码给我看看吗?我的邮箱:472818342@qq.com我对文件指针不了解呢,你的话给了我很大帮助,我自己再研究研究啊。

#11


如果我每次只读入一个数据,但细化的时候需要周边像素数据,那样的话我还是需要读入一个分块吧?

#12


根据5楼的提示,采用CreateFileMapping、MapViewOfFile文件映射的方式做,还是这个办法好,直观、省事,不过比较考验机器的性能,我用了一下午时间,研究了一下,下面给出代码,你自己参考。
// 创建文件内核对象,其句柄保存于hFile 
HANDLE hFile = CreateFile(
lpszPathName,
GENERIC_WRITE|GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING, //注意这里是打开现有的CREATE_ALWAYS新建
FILE_FLAG_SEQUENTIAL_SCAN, 
NULL); 
DWORD dwFileSize;
        // 得到文件的大小
dwFileSize = GetFileSize(hFile,NULL);
// 创建文件映射内核对象,句柄保存于hFileMapping
HANDLE hFileMapping = CreateFileMapping(hFile,
NULL,
PAGE_READWRITE,
0,//(DWORD)(dwBitsSize >> 32), //因为我的文件不可能超过4G,所以我就没有采用__int64类型,
          //而是DWORD类,如果超过4G,请把dwBitsSize定义为__int64,然后采用注释掉的语句就可以了
dwFileSize,//(DWORD)(dwBitsSize & 0xFFFFFFFF),
NULL); 
// 释放文件内核对象
CloseHandle(hFile); 
// 设定大小、偏移量等参数 __int64是long long类型64位整数
__int64 qwFileOffset = 0;
// 将文件数据映射到进程的地址空间 
PBYTE pbFile = (PBYTE)MapViewOfFile(
hFileMapping,FILE_MAP_ALL_ACCESS,
(DWORD)(qwFileOffset>>32), 
(DWORD)(qwFileOffset&0xFFFFFFFF), 
dwFileSize);
BITMAPFILEHEADER bmfHeader; //bmp文件头结构
BITMAPINFO lpDIBHdr; //DIB头结构
PBYTE    lpDIBBits;  //DIB像素数据首地址
//获取bmp文件头数据
memcpy(&bmfHeader,pbFile,sizeof(bmfHeader));
//获取DIB头信息
memcpy(&lpDIBHdr,pbFile+sizeof(bmfHeader), *(pbFile+sizeof(bmfHeader)));
//获得DIB像素首地址
lpDIBBits = pbFile + sizeof(bmfHeader) + *(pbFile+sizeof(bmfHeader));
// 从进程的地址空间撤消文件数据映像
UnmapViewOfFile(pbFile);
// 关闭文件映射对象
CloseHandle(hFileMapping); 
经过验证完全没有问题,你要知道,大部分高手都比较懒,因为他们已经回答过好多遍了,所以都懒得回答太详细的内容,许多时候往往只是提点一句两句,给你提供一个方向,然后就需要你自己去研究,只有这样得来的东西才是自己的,否则拿来就用,往往学的似是而非,学习程序一定要有研究精神,我喜欢回答详细一点是因为我也是初学者,我学C++还不到3个月,学习图像处理也才2个月,只有在回答问题的过程中,才能发现自己没有理解到的地方。

#13


内存映射的话,多大的文件都没问题。当然每次读入多少到内存,取决于你的内存大小。还有就是,你准备如何处理数据,内存映射读入局部到内存,只是文本搜索,很好办,但要是排序,就无能为力了。所以取决于你图像处理如何进行。

如果真要一次性读入1.2G到内存,你就用window sever 2003 64bit或者Win 7做操作系统。

#14


引用 12 楼 zhufeng1001 的回复:
根据5楼的提示,采用CreateFileMapping、MapViewOfFile文件映射的方式做,还是这个办法好,直观、省事,不过比较考验机器的性能,我用了一下午时间,研究了一下,下面给出代码,你自己参考。
// 创建文件内核对象,其句柄保存于hFile 
HANDLE hFile = CreateFile(
lpszPathName,
GENERIC_WRITE|GENERIC_REA……
非常感谢啊。你不仅授之以鱼,还授之以渔。。。我会研究的。。。

#15


如果1.2g只是图像数据,不含文件头信息,可以使用createdibsection,其中hSection参数为数据文件的映射句柄,用CreateFileMapping创建的,还有个参数是设置数据文件的偏移量,以字节为单位,这个好处是可以将图片分块映射成为dib,不占用大量虚拟内存,我试用这种方法显示1.6g图像的,dib是1024*1024像素块.

#16


引用 15 楼 njsf_79 的回复:
如果1.2g只是图像数据,不含文件头信息,可以使用createdibsection,其中hSection参数为数据文件的映射句柄,用CreateFileMapping创建的,还有个参数是设置数据文件的偏移量,以字节为单位,这个好处是可以将图片分块映射成为dib,不占用大量虚拟内存,我试用这种方法显示1.6g图像的,dib是1024*1024像素块.

又学习了,我还在想呢,能计算出图像数据的地址,怎么得到DIB图像的句柄呢,15楼就给出了函数,知识还在于积累和交流。
createdibsection()函数
HBITMAP CreateDIBSection(HDC hdc,CONST BITMAPINFO *pbmi,UINT iUsage,VOID** ppvBits,HANDLE hSection,DWORD dwOffset); 
如果函数执行成功,那么返回值是一个指向刚刚创建的与设备无关位图的句柄,并且*ppvBits指向该位图的位数据值;如果函数执行失败,那么返回值为NULL,并且*ppvBit也为NULL

#17


引用 12 楼 zhufeng1001 的回复:
根据5楼的提示,采用CreateFileMapping、MapViewOfFile文件映射的方式做,还是这个办法好,直观、省事,不过比较考验机器的性能,我用了一下午时间,研究了一下,下面给出代码,你自己参考。
// 创建文件内核对象,其句柄保存于hFile 
HANDLE hFile = CreateFile(
lpszPathName,
GENERIC_WRITE|GENERIC_REA……
我尝试了这段代码,在运行时会在这一步出错://获取bmp文件头数据
memcpy(&bmfHeader,pbFile,sizeof(bmfHeader));
提示读取位置时发生访问冲突。这是为什么?

#18


是否是因为&bmfHeader尚未创建?

#19


引用 12 楼 zhufeng1001 的回复:
根据5楼的提示,采用CreateFileMapping、MapViewOfFile文件映射的方式做,还是这个办法好,直观、省事,不过比较考验机器的性能,我用了一下午时间,研究了一下,下面给出代码,你自己参考。
// 创建文件内核对象,其句柄保存于hFile 
HANDLE hFile = CreateFile(
lpszPathName,
GENERIC_WRITE|GENERIC_REA……
经测试,用这方法可以顺利读取560MB的图片,但读入1.2G图像时会出错,即在memcpy处出错,这是为什么?是因为文件太大,空间不够?

#20


你倒是把你用的memcpy的代码贴出来啊
你不贴怎么知道哪里错了,再说根据我的用法的话
//获取bmp文件头数据
memcpy(&bmfHeader,pbFile,sizeof(bmfHeader));
//获取DIB头信息
memcpy(&lpDIBHdr,pbFile+sizeof(bmfHeader), *(pbFile+sizeof(bmfHeader)));
//获得DIB像素首地址
lpDIBBits = pbFile + sizeof(bmfHeader) + *(pbFile+sizeof(bmfHeader));
sizeof(bmfHeader)和*(pbFile+sizeof(bmfHeader))应该都不大,也就几十字节
lpDIBBits只是一个地址,不涉及大小问题。
要出错也可能是*(pbFile+sizeof(bmfHeader))这个地址的值有问题。
有问题自己追踪把,很可能机器运行的过程和你想象的不一样,调试程序也是非常重要的一步。

#21


引用 20 楼 zhufeng1001 的回复:
你倒是把你用的memcpy的代码贴出来啊
你不贴怎么知道哪里错了,再说根据我的用法的话
//获取bmp文件头数据
memcpy(&bmfHeader,pbFile,sizeof(bmfHeader));
//获取DIB头信息
memcpy(&lpDIBHdr,pbFile+sizeof(bmfHeader), *(pbFile+sizeof(bmfHeader)));
……
//获取bmp文件头数据
memcpy(&bmfHeader,pbFile,sizeof(bmfHeader));
追踪到memcpy.asm中,调试指针指向:UnwindUp3:
        mov     eax,[esi+ecx*4-12] ;U(entry)/V(not) - get dword from source
                                   ;V(entry) - spare
        mov     [edi+ecx*4-12],eax ;U - put dword into destination
我在导入560MB图像都没问题,但到了1G就出错了,我真的搞不懂呢。

#22


追踪到memcpy.asm中,调试指针指向:UnwindUp3:
你追踪这个毫无意义,你只需要查看出错时,sizeof(bmfHeader),pbFile,&bmfHeader这些数据的值就好了
你可以依次察看*(pbFile),*(pbFile+1),*(pbFile+2),。。。。,*(pbFile+sizeof(bmfHeader)-1)的值啊
看看是不是符合你预期的数值,sizeof(bmfHeader)不大,而且是个固定植。
memcpy抱错只可能是你的pbfile当前指针指向有问题,另外如果pbFile是空也会出问题的,加条语句判断一下吧

#23


引用 22 楼 zhufeng1001 的回复:
追踪到memcpy.asm中,调试指针指向:UnwindUp3:
你追踪这个毫无意义,你只需要查看出错时,sizeof(bmfHeader),pbFile,&bmfHeader这些数据的值就好了
你可以依次察看*(pbFile),*(pbFile+1),*(pbFile+2),。。。。,*(pbFile+sizeof(bmfHeader)-1)的值啊
看看是不是符合你预期的数值,si……
我刚断点追踪了,发现是pbFile是错误的指针,这是什么原因呢?是在将文件数据映射到进程的地址空间时出错?是否跟文件的大小和计算机内存有关吗?急求

#24


引用 7 楼 ankeysun 的回复:
额 你这个问题我刚处理过,其实你可以打开文件,用文件指针操作文件里面的数据,1.2G就算文件映射完了,你也得读到缓存,但是没那么大的缓存,就算分段申请,也相对麻烦些,不如打开文件,分开读文件头信息头,然后接着移动文件指针,对数据内容进行一步步处理。我当初是这么实现的,也是处理1.2G的位图。不过有一缺陷,就是1.2G的文件在你打开瞬间还不能立即读,因为机子稍微不好的话,会导致程序崩溃,因为文件在打……


这个方法很好 用文件映射好些,可以处理大的文件