C++读取图片文件

C++读取图片文件

这里主要讲述如何在C++编程中读取图片文件,主要介绍两种方式:一种的是C++风格,主要是采用文件流的方式,另一种是C风格,主要采用FILE类的相关操作。小面分别对两种方式进行介绍。

1、文件流读取图片文件

主要的步骤:

  • 1、打开图片文件;
  • 2、计算图片长度;
  • 3、创建内存缓存区;
  • 4、读取图片。

对应的头文件:

#include <fstream> 

主要用到的函数:

  • 1、ifstream.seekg()
seekg:设置输入文件流的文件流指针位置

seekg()定义:
istream& seekg (streampos pos);//将读指针设置到pos位置
istream& seekg (streamoff off, ios_base::seekdir way);//将读指针设置为way+off
其中off代表偏移值可以是正负数值,正的表示向后偏移,负的表示向前偏移。而way代表基址,可以是:
     ios::beg:表示输入流的开始位置
     ios::cur:表示输入流的当前位置
     ios::end:表示输入流的结束位置
  • 2、ifstream.tellg()
tellg: 用于获取文件流中的文件流指针的位置


//tellg()定义:
streampos tellg();//返回一个整型数,代表读指针的位置
//example:streampos pos = tellg();//将tellg()返回的指针位置赋值给pos
  • 3、ifstream.tellg()
函数原型: read(unsigned char *buf,int num);

read()从文件流中读取num个字符到buf指向的缓存中,如果在还未读入 num个字符时就到了文件尾,可以用成员函数gcount()来取得实际读取的字符数。

代码:

#include <fstream> // ifstream, ifstream::in
using namespace std;

int main(){
	// 1. 打开图片文件
	ifstream is("test.jpg", ifstream::in | ios::binary);
	// 2. 计算图片长度
	is.seekg(0, is.end);  //将文件流指针定位到流的末尾
	int length = is.tellg();
	is.seekg(0, is.beg);  //将文件流指针重新定位到流的开始
	// 3. 创建内存缓存区
	char * buffer = new char[length];
	// 4. 读取图片
	is.read(buffer, length);
	// 到此,图片已经成功的被读取到内存(buffer)中
	delete [] buffer;
	return 0;
}

上述程序中出现了ios::binary,关于文件流ios::binary的作用如下:

在创建文件流时,可以显示指定它的打开方式为ios::binary,也就是以二进制方式打开。但是,无论是否指定二进制方式打开文件,读写的最小单位都是字节。那么,它到底起到什么作用呢?

首先,介绍一下二进制方式打开与普通打开方式的区别,两者大的区别在于对换行符的处理方式不同。由于历史原因,Windows操作系统是用两个字符(\r\n)来表示换行符的;而Unix操作系统却是用单个字符(\n)来表示换行符的。因此,在创建文件流时,如果指定了以ios::binary方式打开,那么换行符就是单字符的;否则,就采用Windows操作系统的双字符。

总结来说,以ios::binary方式打开,换行符被解释成\n;反之,换行符被解释成\r\n。

所以为了兼容性,通常在Windous系统中通常使用ios::binary方式打开图像文件;在Unix(或类Unix)操作系统中,指定和不指定ios::binary方式没有区别。

详细的文件流操作参考链接:https://www.cnblogs.com/hjj-fighting/p/10429178.html

2、FILE操作读取图片文件

1、文件类型指针

  • 这种方式的文件操作需要一个重要的结构体FILE,FILE在头文件stdio.h中定义。
typedef struct { 
  int level;           /* fill/empty level of buffer */ 
  unsigned flags;        /* File status flags */ 
  char fd;            /* File descriptor */ 
  unsigned char hold;      /* Ungetc char if no buffer */ 
  int bsize;           /* Buffer size */ 
  unsigned char _FAR *buffer; /* Data transfer buffer */ 
  unsigned char _FAR *curp;  /* Current active pointer */ 
  unsigned istemp;      /* Temporary file indicator */ 
  short token;          /* Used for validity checking */ 
} FILE;              /* This is the FILE object */ 

 

  • 可以看到这些文件信息都被保存在一个FILE结构类型。通常我们需要先定义一个指向FILE结构体类型的指针变量。
FILE *fp;

2、文件操作常用函数

  • fopen()函数

    • 函数原型为:FILE *fopen(const char *filename, const char *mode);
    • 其中参数filename指向要打开的文件名,mode表示文件打开模式的字符串。函数返回一个指向FILE类型的指针,当打开文件时出现了错误,fopen函数都将返回NULL。

    文件打开模式:

    "r":只能从文件中读数据,该文件必须先存在,否则打开失败。

    "w":只能向文件写数据,若指定的文件不存在则创建它,如果存在则先删除它再重建一个新文件。

    "a":向文件增加新数据(不删除原有数据),若文件不存在则打开失败,打开时位置指针移到文件末尾。

    "r+":可读/写数据,该文件必须先存在,否则打开失败。 "w+":可读/写数据,用该模式打开新建一个文件,先向该文件写数据,然后可读取该文件中的数据。 "a+":可读/写数据,原来的文件不被删去,位置指针移到文件末尾。

    打开二进制文件的模式与打开文本文件的含义是一样的,不同的是模式名称里面多一个字母'b’,以表示以二进制形式打开文件。

  • fclose()函数

    • 函数原型为:int fclose(FILE *);

    • 关闭成功返回值0,否则返回非零值。

    • 在执行完文件的操作后,要进行“关闭文件”操作。虽然程序在结束前会自动关闭所有的打开文件,但文件打开过多会导致系统运行缓慢,这时就要自行手动关闭不再使用的文件,来提高系统整体的执行效率。

文件的读写操作

  • fread()函数
    • 函数原型:unsigned int fread(void *buffer, unsigned int size, unsigned int count, FILE *fp);
    • 函数功能:从fp所指的文件中读取数据块并存储到buffer所指向的内存中,buffer是待读入数据块存储的起始地址,size是每个数据块的大小(待读入的每个数据块的字节数),count是最多允许读取的数据块个数(每个数据块size个字节),函数返回的是实际读到的数据块个数。
  • fwrite()函数
    • 函数原型:unsigned int fwrite(const void *buffer, unsigned int size, unsigned int count, FILE *fp);
    • 函数功能:将buffer指向的内存中的数据块写入fp所指的文件,buffer是待输出数据块的起始地址,size是每个数据块的大小(待输出的每个数据块的字节数),count是最多允许写入的数据块个数(每个数据块size个字节),函数返回的是实际写入的数据块个数。
  • fread()函数和fwrite()函数是按数据块的长度来处理输入/输出的,在用文本编辑器打开文本文件时可能因发生字符转换而出现莫名其妙的结果,所以这两个函数通常用于二进制文件的输入/输出。
  • fscanf()函数
    • 函数原型:int fscanf (FILE *fp, const char *format, ……);
    • 第一个参数为文件指针,第二个参数为格式控制符,第三个参数为地址参数表列,后两个参数与函数scanf()的参数相同。
  • fprintf()函数
    • 函数原型:int fprintf (FILE *fp, onst char *format, ……);
    • 第一个参数为文件指针,第二个参数为格式控制参数,第三个参数为输出参数列表,后两个参数和返回值与函数printf()相同。
  • 用函数fscanf()和fprintf()进行文件的格式化读写,读写方便容易理解,但输入时要将ASCII字符转换成二进制数,输出时要将二进制数转换为ASCII字符,耗时较多。
  • fgets()函数
    • 函数原型:char *fgets(char *s,int n,FILE *fp);
    • 函数功能:该函数从fp所指的文件中读取字符串并在字符串末尾添加‘\0’,然后存入s,最多读n-1个字符,当读到回车换行符、到达文件尾或读满n-1个字符时,就停止读取。
    • 函数返回该字符串的首地址,即指针s的值,读取失败返回空指针NULL。
    • 与gets()不同的是,fgets()从指定的流读取字符串,读到换行符时将换行符也作为字符串的一部分读到字符串中来。
  • fputs()函数
    • 函数原型:fputs(In_z const char * _Str, Inout FILE * _File);
    • 其中str是要输出的字符串,fp是文件指针,字符串末尾'\0'不输出。
    • 函数功能:将字符串输出到指针fp所指的文件中。
    • 与puts()不同的是,fputs()不会在写入文件的字符串末尾加上换行符'\n'。
  • fgetc()函数
    • 函数原型:int fgetc (FILE *fp);
    • 函数功能:用于从一个以只读或读写方式打开的文件上读字符,从fp所指的文件中读取一个字符,并将位置指针指向下一个字符,若读取成功,则返回该字符,若读取不成功则返回EOF(EOF是一个符号常量,stdio.h中定义为-1) 。
  • fputc()函数
    • 函数原型:int fputc(int c, FILE *fp);
    • fp是由函数fopen()返回的文件指针,c是要输出的字符(尽管C定义为int型,但只写入低字节)。
    • 函数功能:该函数的功能是将字符c写到文件指针fp所指的文件上中,若写入错误返回EOF,否则返回字符c 。

文件的定位

  • 为了实现文件的定位,在每一个打开的文件中,都有一个文件位置指针,也称为文件位置标记,用来指向当前读写文件的位置,它保存了文件中的位置信息,当文件进行顺序读写时,每读完一个字节后,该位置指针自动移到下一个字节的位置,当需要随机读写文件数据时,则需强制移动文件位置指针指向特定的位置。
  • fseek()函数
    • 函数功能:将fp的文件位置指针从fromwhere开始移动offset个字节指示下一个要读取的数据的位置。
    • ffset是一个偏移量,它告诉文件位置指针要跳过多少字节,offset为正时,向后移动,为负时,向前移动,ANSIC要求位移量offset是长整型数据(常量数据后要加L)。
    • fromwhere用于确定偏移量计算的起始位置,它的可能取值有3种,SEEK_SET或0,代表文件开始处,SEEK_CUR或1,代表文件当前位置,SEEK_END或2,代表文件结尾处。
    • 通过指定fromwork和offset的值,可使位置指针移动到文件的任意位置,从而实现文件的随机读取,如果函数fseek()调用成功,则返回0值,否则返回非0值。
    • fseek() 一般用于二进制文件,在文本文件中由于要进行转换,计算的位置有时会出错。
  • rewind()函数
    • 函数原型:void rewind(FILE *fp);
    • 函数功能:将文件位置指针指向文件首字节,即重置位置指针到文件首部。
  • ftell()函数
    • 函数原型:long ftell(FILE *fp);
    • 函数功能:读取当前文件指针的位置,若函数调用成功,则返回文件的当前读写位置,否则返回-1L,函数ftell()用于相对于文件起始位置的字节偏移量来表示返回的当前位置指针。

代码

#include <stdio.h> 
using namespace std;

int main(){
    FILE *in;
	// 1. 打开图片文件
    int = fopen(path, "rb")
	ifstream is("test.jpg", ifstream::in | ios::binary);
	// 2. 计算图片长度
	fseek(in, 0L, SEEK_END);
    int len =  ftell(in);
    fseek(in, 0L, SEEK_SET);
	// 3. 创建内存缓存区
	char * buffer = new char[length];
	// 4. 读取图片
	fread(buffer, sizeof(char), len, in);
    fclose(in);
	// 到此,图片已经成功的被读取到内存(buffer)中
	delete [] buffer;
	return 0;
}

参考链接

https://www.cnblogs.com/lanhaicode/p/10320097.html

https://blog.csdn.net/qq_29695701/article/details/84262492

  • 22
    点赞
  • 172
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值