当前位置:网站首页 > 编程语言 > 正文

读取文件为byte(读取文件为什么size=1)



文件(file)通常是在磁盘或固态硬盘上的一段已命名的存储区。C把文件看作是一系列连续的字节,每个字节都能被单独读取。所有文件的内容都以二进制形式(0或1)储存。

为了规范文本文件的处理,C 提供两种访问文件的途径:二进制模式和文本模式。

二进制模式:程序可以访问文件的每个字节。

文本模式:程序所见的内容和文件的实际内容不同。程序以文本模式读取文件时,把本地环境表示的行末尾或文件结尾映射为C模式。

除了选择文件的模式,大多数情况下,还可以选择I/O的两个级别(即处理文件访问的两个级别)

因为无法保证所有的操作系统都使用相同的底层I/O模型,C标准只支持标准I/O包。有些实现会提供底层库,但是C标准建立了可移植的I/O模型,我们主要讨论这些I/O。

两个级别:

(1)底层I/O(low-level I/O)使用操作系统提供的基本I/O服务。

(2)标准高级I/O(standard high-level I/O)使用C库的标准包和stdio.h头文件定义。

与底层I/O相比,标准I/O三个优点:

可移植性。包含很多专用函数,方便处理不同问题。对输入和输出进行了缓冲,提高传输效率。

C程序会自动打开3个文件,它们被称为标准输入、标准输出和标准错误输出 。在默认情况下,标准输入是系统的普通输入设备,通常为键盘;标准输出和标准错误输出是系统的普通输出设备,通常为显示屏。

exit()函数关闭所有打开的文件并结束程序。exit()的参数被传递给一些操作系统,包括 UNIX、Linux、Windows和MS-DOS,以供其他程序使用。

通常的惯例是:正常结束的程序传递0,异常结束的程序传递非零值。不同的退出值可用于区分程序失败的不同原因,这也是UNIX和DOS编程的通常做法。但是,并不是所有的操作系统都能识别相同范围内的返回值。因此,C 标准规定了一个最小的限制范围。标准要求0或宏EXIT_SUCCESS用于表明成功结束程序,宏EXIT_FAILURE用于表明结束程序失败。这些宏和exit()原型都位于stdlib.h头文件中。

如果main()在一个递归程序中,exit()仍然会终止程序,return和exit()的一个区别是,即使在其他函数中(除main()以外)调用exit()也能结束整个程序。

原型:FILE * fopen (const char *, const char *);

第一个参数:待打开文件的名称,更确切地说是一个包含该文件名的字符串地址。

第二个参数:一个字符串,指定待打开文件的模式。

像UNIX和Linux这样只有一种文件类型的系统,带b字母的模式和不带b字母的模式相同。

将返回文件指针,文件指针的类型是指向FILE的指针,FILE是一个定义在stdio.h中的派生类型。文件指针并不指向实际的文件,它指向一个包含文件信息的数据对象,其中包含操作文件的I/O函数所用的缓冲区信息。因为标准库中的I/O函数使用缓冲区,所以它们不仅要知道缓冲区的位置,还要知道缓冲区被填充的程度以及操作哪一个文件。标准I/O函数根据这些信息在必要时决定再次填充或清空缓冲区。

两组函数功能和用法没有明显差距。

原型:int getc (FILE *);     int  fgetc (FILE *);

从标准输入中获取一个字符:ch = getchar();

从fp指定的文件中获取一个字符:ch = getc(fp);

在读取一个字符时发现是文件结尾,它将返回一个特殊值EOF。

原型:int    fputc (int, FILE *);    int putc (int, FILE *);

putc(ch, fpout);第1个参数是待写入的字符,第2个参数是文件指针,把字符ch放入FILE指针fpout指定的文件中。

关闭fp指定的文件,必要时刷新缓冲区。

返回值:成功关闭,返回0,否则返回EOF

示例:

if (fclose(fp) != 0)

printf("Error in closing file %s ", argv[1]);

如果磁盘已满、移动硬盘被移除或出现I/O错误,都会导致调用fclose()函数失败。

文件I/O函数fprintf()和fscanf()函数的工作方式与printf()和scanf()类似,区别在于前者需要用第1个参数指定待处理的文件。

原型:char *fgets(char *str, int n, FILE *stream);

读取输入直到第 1 个换行符的后面,或读到文件结尾,或者读取n-1 个字符。

第1个参数表示储存输入位置的地址(char * 类型);第2个参数是一个整数,表示待输入字符串的大小 ;最后一个参数是文件指针,指定待读取的文件。

原型:int   fputs (const char *, FILE *);

根据传入地址找到的字符串写入指定的文件中。不会在其末尾添加换行符。

fseek()和 ftell()潜在的问题是,它们都把文件大小限制在 long 类型能表示的范围内。

fseek()函数

原型:int   fseek (FILE *, long, int);

第1个参数是FILE指针,指向待查找的文件,fopen()应该已打开该文件。第2个参数是偏移量。该参数表示从起始点开始要移动的距离。该参数必须是一个long类型的值,可以为正(前移)、负(后移)或0(保持不动)。第3个参数是模式,该参数确定起始点。根据ANSI标准,在stdio.h头文件中规定了几个表示模式的明示常量,如表所示。

示例:

fseek(fp, 0L, SEEK_SET); // 定位至文件开始处

fseek(fp, 10L, SEEK_SET); // 定位至文件中的第10个字节

fseek(fp, 2L, SEEK_CUR); // 从文件当前位置前移2个字节

fseek(fp, 0L, SEEK_END); // 定位至文件结尾

fseek(fp, -10L, SEEK_END); // 从文件结尾处回退10个字节

ftell()函数

返回类型是long,它返回的是当前的位置。

通过返回距文件开始处的字节数来确定文件的位置。文件的第1个字节到文件开始处的距离是0,以此类推。ANSI C规定,该定义适用于以二进制模式打开的文件,以文件模式打开文件的情况不同。

ftell()函数在文本模式和二进制模式中的工作方式不同。许多系统的文本文件格式与UNIX的模型有很大不同,导致从文件开始处统计的字节数成为一个毫无意义的值。ANSI C规定,对于文本模式,ftell()返回的值可以作为fseek()的第2个参数。对于MS-DOS,ftell()返回的值把 当作一个字节计数。

可移植性

理论上,fseek()和ftell()应该符合UNIX模型。但是,不同系统存在着差异,有时确实无法做到与UNIX模型一致。因此,ANSI对这些函数降低了要求。下面是一些限制。在二进制模式中,实现不必支持SEEK_END模式。因此无法保证程序的可移植性。移植性更高的方法是逐字节读取整个文件直到文件末尾。C 预处理器的条件编译指令提供了一种系统方法来处理这种情况。在文本模式中,只有以下调用能保证其相应的行为。

ANSI C新增了两个处理较大文件的新定位函数:fgetpos()和 fsetpos()。这两个函数不使用 long 类型的值表示位置,它们使用一种新类型:fpos_t(代表file position type,文件定位类型)。fpos_t类型不是基本类型,它根据其他类型来定义。fpos_t 类型的变量或数据对象可以在文件中指定一个位置,它不能是数组类型,除此之外,没有其他限制。实现可以提供一个满足特殊平台要求的类型,例如,fpos_t可以实现为结构。

fgetpos()函数

原型:int fgetpos(FILE * restrict stream, fpos_t * restrict pos);

调用该函数时,它把fpos_t类型的值放在pos指向的位置上,该值描述了文件中的一个位置。如果成功,fgetpos()函数返回0;如果失败,返回非0。

fsetpos()函数

原型:int fsetpos(FILE *stream, const fpos_t *pos);

调用该函数时,使用pos指向位置上的fpos_t类型值来设置文件指针指向该值指定的位置。如果成功,fsetpos()函数返回0;如果失败,则返回非0。fpos_t类型的值应通过之前调用fgetpos()获得。

调用fopen()打开文件,创建了一个缓冲区(在读写模式下会创建两个缓冲区)以及一个包含文件和缓冲区数据的结构。返回一个指向该结构的指针,以便其他函数知道如何找到该结构。假设把该指针赋给一个指针变量fp,我们说fopen()函数“打开一个流”。如果以文本模式打开该文件,就获得一个文本流;如果以二进制模式打开该文件,就获得一个二进制流。

这个结构通常包含一个指定流中当前位置的文件位置指示器。除此之外,它还包含错误和文件结尾的指示器、一个指向缓冲区开始处的指针、一个文件标识符和一个计数(统计实际拷贝进缓冲区的字节数)。

调用一个定义在stdio.h中的输入函数,如fscanf()、getc()或 fgets()。一调用这些函数,文件中的数据块就被拷贝到缓冲区中。缓冲区的大小因实现而异,一般是512字节或是它的倍数,如4096或16384(随着计算机硬盘容量越来越大,缓冲区的大小也越来越大)。

最初调用函数,除了填充缓冲区外,还要设置fp所指向的结构中的值。尤其要设置流中的当前位置和拷贝进缓冲区的字节数。通常,当前位置从字节0开始。在初始化结构和缓冲区后,输入函数按要求从缓冲区中读取数据。在它读取数据时,文件位置指示器被设置为指向刚读取字符的下一个字符。由于stdio.h系列的所有输入函数都使用相同的缓冲区,所以调用任何一个函数都将从上一次函数停止调用的位置开始。当输入函数发现已读完缓冲区中的所有字符时,会请求把下一个缓冲大小的数据块从文件拷贝到该缓冲区中。以这种方式,输入函数可以读取文件中的所有内容,直到文件结尾。函数在读取缓冲区中的最后一个字符后,把结尾指示器设置为真。于是,下一次被调用的输入函数将返回EOF。输出函数以类似的方式把数据写入缓冲区。当缓冲区被填满时,数据将被拷贝至文件中。

原型:int ungetc(int c, FILE *fp);

把c指定的字符放回输入流中。如果把一个字符放回输入流,下次调用标准输入函数时将读取该字符。保证每次只会放回一个字符。

原型:int fflush(FILE *fp);

调用函数引起输出缓冲区中所有的未写入数据被发送到fp指定的输出文件。这个过程称为刷新缓冲区。如果 fp是空指针,所有输出缓冲区都被刷新。在输入流中使用fflush()函数的效果是未定义的。只要最近一次操作不是输入操作,就可以用该函数来更新流(任何读写模式)。

原型:int setvbuf(FILE * restrict fp, char * restrict buf, int mode, size_t size);

创建了一个供标准I/O函数替换使用的缓冲区。在打开文件后且未对流进行其他操作之前,调用该函数。指针fp识别待处理的流,buf指向待使用的存储区。如果buf的值不是NULL,则必须创建一个缓冲区。例如,声明一个内含1024个字符的数组,并传递该数组的地址。然而,如果把NULL作为buf的值,该函数会为自己分配一个缓冲区。变量size告诉setvbuf()数组的大小mode的选择如下:_IOFBF表示完全缓冲(在缓冲区满时刷新);_IOLBF表示行缓冲(在缓冲区满时或写入一个换行符时);_IONBF表示无缓冲。如果操作成功,函数返回0,否则返回一个非零值。假设一个程序要储存一种数据对象,每个数据对象的大小是3000字节。可以使用setvbuf()函数创建一个缓冲区,其大小是该数据对象大小的倍数。

之前用到的标准I/O函数都是面向文本的,用于处理字符和字符串。用 fprintf()函数和%f转换说明只是把数值保存为字符串,这种转换可能会改变值。

所有的数据都是以二进制形式储存的,甚至连字符都以字符码的二进制表示来储存。如果文件中的所有数据都被解释成字符码,则称该文件包含文本数据。如果部分或所有的数据都被解释成二进制形式的数值数据,则称该文件包含二进制数据(另外,用数据表示机器语言指令的文件都是二进制文件)。

原型:size_t fwrite(const void * restrict ptr, size_t size, size_t nmemb,FILE * restrictfp);

把二进制数据写入文件。

第1个参数不是固定的类型。例如,可以是指向char的指针;也可以是指向double的指针。在ANSI C函数原型中,这些实际参数都被转换成指向void的指针类型,这种指针可作为一种通用类型指针(在ANSI C之前,这些参数使用char*类型,需要把实参强制转换成char *类型)。fwrite()函数返回成功写入项的数量。正常情况下,该返回值就是nmemb,但如果出现写入错误,返回值会比nmemb小。

原型:size_t fread(void * restrict ptr, size_t size, size_t nmemb,FILE * restrict fp);

ptr是待读取文件数据在内存中的地址,fp指定待读取的文件。该函数用于读取被fwrite()写入文件的数据。例如,要恢复上例中保存的内含10个double类型值的数组,可以这样做:

double earnings[10];

fread(earnings, sizeof (double), 10, fp);  //把10个double大小的值拷贝进earnings数组中。

返回成功读取项的数量。正常情况下,该返回值就是nmemb,但如果出现读取错误或读到文件结尾,该返回值就会比nmemb小。

原型:int feof(FILE *fp);和int ferror(FILE *fp);

如果标准输入函数返回 EOF,则通常表明函数已到达文件结尾。然而,出现读取错误时,函数也会返回EOF。feof()和ferror()函数用于区分这两种情况。当上一次输入调用检测到文件结尾时,feof()函数返回一个非零值,否则返回0。当读或写出现错误,ferror()函数返回一个非零值,否则返回0。

到此这篇读取文件为byte(读取文件为什么size=1)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!

版权声明


相关文章:

  • 网页传输文件的网站(网页传输文件的网站叫什么)2025-09-01 08:09:10
  • 怎么把支付指纹改成支付密码(怎样将指纹支付改为密码支付)2025-09-01 08:09:10
  • py文件(py文件怎么打包成exe)2025-09-01 08:09:10
  • 启动盘u盘制作win7(制作u盘启动win7系统)2025-09-01 08:09:10
  • 操作系统 题(操作系统题目和答案百度网盘)2025-09-01 08:09:10
  • ssh免密操作(ssh 免密)2025-09-01 08:09:10
  • 手机号被恶意发送短信验证码,怎么办(手机被恶意发送验证码可以报警吗)2025-09-01 08:09:10
  • 增删改查是什么功能(增删改查是ddl还是dml)2025-09-01 08:09:10
  • 网上聊天网页(网上聊天网页没有本地记录)2025-09-01 08:09:10
  • 跨区域物流(跨区域物流调研报告)2025-09-01 08:09:10
  • 全屏图片