C++ /文件流 /BMP文件读写

来源:互联网 发布:tomcat连接sql server 编辑:程序博客网 时间:2024/05/17 08:48

C++文件流

C++ 通过以下几个类支持文件的输入输出:

  • ofstream: 写操作(输出)的文件类 (由ostream引申而来)
  • ifstream: 读操作(输入)的文件类(由istream引申而来)
  • fstream: 可同时读写操作的文件类 (由iostream引申而来)

文件输出流:

ofstream 类支持磁盘文件输出。如果程序需要把数据信息输出到磁盘文件,可以构造一个ofstream 类的对象。在定义流对象的同时,指定相关联的文件;也可以先定义流对象,随后调用open成员函数,指定相关联的文件并打开。常用方法如下:
  • 在调用构造函数时指定文件名,直接将文件流对象和磁盘文件相关联:                                                               
    ofstream("filename.dat");

  • 使用默认构造函数创建对象,再调用 open 成员函数建立对象和文件的关联:
    ofstream f1;// 定义一个输出文件流对象f1.open(<span style="font-family: Arial, Helvetica, sans-serif;">"filename.dat"</span><span style="font-family: Arial, Helvetica, sans-serif;">);//打开文件,使流对象与文件建立关联</span>
    也可以使用指针形式:
    ofstream* pf = new ofstream;pf->open("filename.dat",iosmode);
然后就可以使用插入运算符,把数据输出到文件,例如:
f1<<"absdkf"<<endl;// 字符串写入文件f1<<i<<endl; // 变量 i 写入文件

open 函数:

open 函数的参数通常要指定一个文件名,另外还要指定一个open_mode标志,如下表:
输出文件流的文件打开模式标志功能ios::app打开输出文件,尾部添加,若不存在则新建ios::ate打开现存文件(入/出),并查找到结尾ios::in打开输入文件,默认模式,可避免现有内容被删除ios::out打开输出文件,默认模式ios::nocreate存在则打开,否则操作失败ios::noreplace不存在则新建并打开,否则操作失败ios::trunc打开,存在则删除已有内容。若指定了ios::out,但没有指定ios::ate/ios::app/ios::in则隐含为此模式ios::binary二进制模式打开文件(默认是文本模式)















put 函数:

把一个字符写到输出流中:
cout.put('c'); // 输出一个字符cout<<'c'; // 输出一个字符,但是此前设置的宽度和填充方式在此起作用

write 函数:

把内存中的一块儿内容写到一个输出文件中,该函数有两个参数:一个char指针(指向内存数据的起始地址)和一个所写字节数。常用于二进制文件的输出。(\(^o^)/~这个很有用哦)
注意:当用write 函数输出数据时,如果文件是按照binary模式打开,写到文件的数据和输出的数据完全相同。但是,如果文件是按照文本模式打开的,当输出整数10,即二进制数00001010 时,系统会认为它是ASCII字符回车,并且自动加上一个ASCII 字符00001101 ,也就是换行。变为将”回车换行“输出到文件。所以,用write 函数输出数据时,文件应该按照binary模式打开。

seekp 和 tellp 函数:

seekp 把位置指针设置到某位置,tellp返回当前指针位置。(可参考下面的程序1)

close 函数:

与open 相对应,把输出文件流关联的磁盘文件关闭。一般来讲,输出流析构函数会自动关闭流关联的文件,不必显示调用,但是如果要在同一个流对象上打开另外的文件,就需要close 函数。

================================================================================================================================

文件输入流:

从磁盘文件读取数据。

read 函数:

从一个文件 把字节流读到一个指定的存储区,当读了指定的字节数或者遇到文件结束符时读结束。

seekg 和 tellg 函数:

在输入文件流中,保存着一个指向下一个将要读取数据的位置的内部指针,可以用seekg来设置这个指针。
tellg 返回当前文件读指针的位置,这个值是streampos类型,定义在iostream.h文件中。

==================================================================================================================================

几个栗子:

1、指针定位,文件长度获取,文件读写

// -----------------------------------------------------------------------------------------// Function:读取一个视频文件,然后将该视频文件另存为。// -----------------------------------------------------------------------------------------#include<iostream>#include <fstream>const int LENGTH = 32*1024;using namespace std;void main(){char buff[LENGTH];streamoff  curpos;streamoff endpos;streamoff  length;int flag =1;int count=0;ifstream srcfile("1.avi",ios::binary);ofstream destfile("11.avi",ios::binary|ios::app);while(flag){curpos=srcfile.tellg();// 获取当前读指针位置 // 成功才会是正常值,否则是-1srcfile.seekg(0,ios::end);// 将读指针放置于文件末尾endpos=srcfile.tellg();length=endpos-curpos;srcfile.seekg(curpos);// 恢复当前读指针if (length>=LENGTH){srcfile.read(buff,LENGTH );destfile.write(buff,LENGTH);// 前面说过,使用write时,需要用binary模式打开。count+=LENGTH/1024;cout<<"本次发送:"<<LENGTH/1024<<" KB ;  "<<"总发送:"<<count<<" KB  "<<endl;}else{srcfile.read(buff,length);destfile.write(buff,length);count+=length/1024;cout<<"本次发送:"<<length/1024<<" KB ;  "<<"总发送:"<<count<<" KB  "<<endl;flag=0;}}char wbp=getchar();}

2、变量写入文件,文件数据排版

//----------------------------------------------------------------------------------------------------------------------// Function: 建立一个大数组,写入数据,然后存到磁盘文件;将磁盘文件数据读入到大数组中。//----------------------------------------------------------------------------------------------------------------------#include <iostream>#include <fstream>using namespace std;struct Point2f{float x;float y;};struct Point2fv{float x;float y;};Point2fv PicAndPoint[6][4];Point2fv testP[6][4];void main(){for (int i=0;i<3;++i){for (int j=0;j<2;++j){PicAndPoint[2*i+j][0].x= -1+j;PicAndPoint[2*i+j][0].y= 1/3.0-i*2/3.0;PicAndPoint[2*i+j][1].x=0+j;PicAndPoint[2*i+j][1].y=1/3.0-i*2/3.0;PicAndPoint[2*i+j][2].x=0+j;PicAndPoint[2*i+j][2].y=1-i*2/3.0;PicAndPoint[2*i+j][3].x= -1+j;PicAndPoint[2*i+j][3].y=1-i*2/3.0;}}ofstream destfile("F:\\conversion.txt", ios::app);for (int i=0;i<6;++i){for (int j=0;j<4;++j){destfile<<PicAndPoint[i][j].x<<" "<<PicAndPoint[i][j].y<<"\n"; // 此处有回车符}}destfile.close();ifstream srctfile("F:\\conversion.txt", ios::in);for (int i=0;i<6;++i){for (int j=0;j<4;++j){srctfile>>testP[i][j].x>>testP[i][j].y; // 忽略了回车符}}srctfile.close();}



3、位图文件(BMP)的存储

截屏神马的可以参考这里的代码。
用到#include <gl.h>  #include <glut.h>
void saveSceneImage(int x,int y,int width, int height)  {  //glGetIntegerv(GL_VIEWPORT,ViewPort);  int ColorChannel = 3;  // 位图文件通道数,RGBint bufferSize = width*height*sizeof(GLubyte)*ColorChannel;  char * ImgData = new char[bufferSize];   // OpenGL 相关glPixelStorei(GL_UNPACK_ALIGNMENT,4);   // 4字节对齐glReadPixels(x,y,width,height,GL_RGB,GL_UNSIGNED_BYTE,ImgData);  //从图像缓存里读取一块数据到内存BITMAPFILEHEADER hdr;  BITMAPINFOHEADER infoHdr;  // 我们只需要关心位图的尺寸,其他值默认就好了infoHdr.biSize = sizeof(BITMAPINFOHEADER);  infoHdr.biWidth =width;  infoHdr.biHeight = height;  infoHdr.biPlanes = 1;  infoHdr.biBitCount = 24;  infoHdr.biCompression = 0;  infoHdr.biSizeImage =width*height*3;  infoHdr.biXPelsPerMeter = 0;  infoHdr.biYPelsPerMeter = 0;  infoHdr.biClrUsed = 0;  infoHdr.biClrImportant = 0;  hdr.bfType = 0x4D42;  hdr.bfReserved1 = 0;  hdr.bfReserved2 = 0;  hdr.bfOffBits = 54;  hdr.bfSize =(DWORD)(sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+width* height * 3);  ofstream destfile("F:\\snap.bmp",ios::binary | ios::app);// app模式,依次写入BITMAPFILEHEADER、BITMAPINFOHEADER和图像数据destfile.write((char*)&hdr,sizeof(BITMAPFILEHEADER));  //destfile.seekp(sizeof(BITMAPFILEHEADER));destfile.write((char*)&infoHdr,sizeof(BITMAPINFOHEADER));  //destfile.seekp(sizeof(BITMAPINFOHEADER));destfile.write((char*)ImgData,width* height * 3);  delete[] ImgData;}  

补充:
OpenGL提供了简洁的函数来操作像素:
glReadPixels
:读取一些像素。当前可以简单理解为把已经绘制好的像素(它可能已经被保存到显卡的显存中)读取到内存
glDrawPixels
:绘制一些像素。当前可以简单理解为把内存中一些数据作为像素数据,进行绘制
glCopyPixels
:复制一些像素。当前可以简单理解为把已经绘制好的像素从一个位置复制到另一个位置。虽然从功能上看,好象等价于先读取像素再绘制像素,但实际上它不需要把已经绘制的像素(它可能已经被保存到显卡的显存中)转换为内存数据,然后再由内存数据进行重新的绘制,所以要比先读取后绘制快很多。

0 0