标准I/O文件编程

 

标准I/O又称为带缓存的I/O,标准I/O库是由ANSI C标准进行规范和说明的,基本所有的操作系统上都支持此库。标准I/O库处理了很多细节,例如,缓存分配、优化长度执行I/O等。这样,用户不必担心如何选择使用正确的块长度。标准I/O库是在系统调用函数基础上构造的,它便于用户使用,但是如果不较深入地了解库的操作,也会带来一些问题。

 

1.流和FILE对象

    缓冲型文件系统把每个设备都转换成一个逻辑设备,叫做流。所有的流具有相同的行为。流基本上与设备无关。有两种类型的流:文本流和二进制流。

所有的初级I/O函数都是针对文件描述符的。当打开一个文件时,即返回一个文件描述符,然后该文件描述符就用于后续的I/O操作。而对于标准I/O库,它们的操作则是围绕流(stream)进行的。

当用标准I/O库打开或创建一个文件时,会使一个流与一个文件相结合。当打开一个流时,标准I/O函数fopen返回一个指向FILE对象的指针。该对象通常是一个结构,它包含了I/O库为管理该流所需要的所有信息:用于实际I/O的文件描述符、指向流缓存的指针、缓存的长度、当前在缓存中的字符数、出错标志等。

应用程序没有必要检验FILE对象。为了引用一个流,需将FILE指针作为参数传递给每个标准I/O函数。在本书中,我们称指向FILE对象的指针(类型为FILE  *)为文件指针。

 

2.文件概述

所谓“文件”,是指一组相关数据的有序集合,这个数据集叫做文件,数据集的名字叫做文件名。实际上在前面的各章中我们已经多次使用了文件,例如源程序文件、目标文件、可执行文件、库文件 (头文件)等。

    文件通常是驻留在外部介质(如磁盘等)上的,在使用时才调入内存中。从不同的角度可对文件进行不同的分类。从用户的角度看,文件可分为普通文件和设备文件两种。

    普通文件是指驻留在磁盘或其他外部介质上的一个有序数据集,可以是源文件、目标文件、可执行程序,也可以是一组待输入处理的原始数据,或者是一组输出的结果。对于源文件、目标文件、可执行程序可以称为程序文件,对输入输出数据可称为数据文件。

设备文件是指与主机相联的各种外部设备,如显示器、打印机、键盘等。在操作系统中,把外部设备也看做是一个文件来进行管理,把它们的输入、输出等同于对磁盘文件的读和写。

    通常把显示器定义为标准输出文件,一般情况下,在屏幕上显示有关信息就是向标准输出文件输出。如前面经常使用的printf函数就是这类输出。

通常把键盘定义为标准输入文件,从键盘上输入就意味着从标准输入文件上输入数据。scanf函数就属于这类输入。

从文件编码的方式来看,文件可分为ASCII码文件和二进制码文件两种。ASCII文件也称为文本文件,这种文件在磁盘中存放时每个字符对应一个字节,用于存放对应的ASCII码。

例如,数5678的存储形式为:

ASCII码:        00110101  00110110  00110111  00111000

                  ↓        ↓         ↓        ↓

十进制码:        5          6         7          8

共占用4个字节。

ASCII码文件可在屏幕上按字符显示。例如,源程序文件就是ASCII文件,由于是按字符显示,因此,人们能读懂其文件内容。

    二进制文件是按二进制的编码方式来存放文件的。

例如, 数5678的存储形式为:

    00010110  00101110

只占2个字节。二进制文件虽然也可在屏幕上显示,但其内容无法读懂。C系统在处理这些文件时,并不区分类型,都看成是字符流,按字节进行处理。

输入/输出字符流的开始和结束只由程序控制而不受物理符号(如回车符)的控制,因此也把这种文件称为“流式文件”。

    流式文件的操作主要有打开、关闭、读、写、 定位等各种操作。

 

1.1 文件打开方式

1.文件打开的方式

标准I/O库打开文件的方式共有12种,表10-1列出了文件的打开方式及其意义说明。

表10-1 文件打开方式表

 文件打开方式

              意义说明

    rt

   只读打开一个文本文件,只允许读数据

    wt

   只写打开或建立一个文本文件,只允许写数据

    at

   追加打开一个文本文件,并在文件末尾写数据

    rb

   只读打开一个二进制文件,只允许读数据

    wb

   只写打开或建立一个二进制文件,只允许写数据

    ab

   追加打开一个二进制文件,并在文件末尾写数据

    rt+

   读写打开一个文本文件,允许读和写

    wt+

   读写打开或建立一个文本文件,允许读写

    at+

   读写打开一个文本文件,允许读,或在文件末追加数据

    rb+

   读写打开一个二进制文件,允许读和写

    wb+

   读写打开或建立一个二进制文件,允许读和写

    ab+

   读写打开一个二进制文件,允许读,或在文件末追加数据

 

2.文件打开方式说明

对于文件的打开方式,有以下几点说明:

文件的打开方式由r、w、a、t、b、+共6个字符组成,各字符的含义如下:

①       r(read)  : 读。

②       w(write) : 写。

③       a(append): 追加。

④       t(text)  : 文本文件,可省略不写。

⑤       b(banary): 二进制文件。

⑥       +:         读和写。

凡用"r"打开一个文件时,该文件必须已经存在,且只能从该文件读出。

用"w"打开的文件只能向该文件写入。若打开的文件不存在,则以指定的文件名建立该文件,若打开的文件已经存在,则将该文件删去,重建一个新文件。

若要向一个已存在的文件追加新的信息,只能用"a"方式打开文件。但此时该文件必须是存在的,否则将会出错。

在打开一个文件时,如果出错,fopen将返回一个空指针值NULL。在程序中可以用这一信息来判别是否完成打开文件的工作,并做相应的处理。

把一个文本文件读入内存时,要将ASCII码转换成二进制码,而把文件以文本方式写入磁盘时,也要把二进制码转换成ASCII码。因此,文本文件的读写要花费较多的转换时间,而对二进制文件的读写则不存在这种转换。

标准输入文件(键盘)、标准输出文件(显示器)、标准出错输出(显示器)是由系统打开的,可直接使用。

 

3.标准I/O文件函数分类说明

表10-2列出标准I/O文件函数的分类及其简要说明。

表10-2 标准I/O文件函数分类表

文件函数分类

              函数名称

打开关闭文件函数

fopen()和fclose()

字符读写函数

fgetc()和fputc()

字符串读写函数

fgets()和fputs()

数据块读写函数

fread()和fwrite()

格式化读写函数

fprintf()和fscanf()

取得文件流的读取位置

ftell()

移动文件流的读写位置

fseek()

文件结束检测函数

feof()

1.2 标准I/O函数说明及程序范例

1.   打开关闭文件

(1) 函数原型

             fopen(打开文件)

 

 

所需头文件

#include <stdio.h>

函数说明

根据文件路径打开文件

函数原型

FILE * fopen(const char * path, const char * mode)

函数传入值

path:打开的文件路径及文件名

mode:代表流的形态。参见文件处理方式

函数返回值

成功:指向该流的文件指针就会被返回

出错:返回NULL,并把错误代码存在errno 中

 

                  fdopen(将文件描述符转为文件指针)

 

 

所需头文件

#include <stdio.h>

函数说明

fdopen()会将参数fildes的文件描述符转换为对应的文件指针后返回

函数原型

FILE * fdopen(int fildes,const char * mode)

函数传入值

fildes:文件描述符

mode: 代表文件指针的流形态,此形态必须和原先文件描述符读写模式相同。mode方式参见文件处理方式

函数返回值

成功:转换成功时返回指向该流的文件指针

错误:返回NULL,并把错误代码存在errno中

 

                  freopen(打开文件)

 

 

所需头文件

#include  <stdio.h>

函数说明

参数path字符串包含欲打开的文件路径及文件名,参数mode请参考fopen()说明。参数stream为已打开的文件指针。freopen()会将原stream所打开的文件流关闭,然后打开参数path的文件

函数原型

FILE * freopen(const char * path,const char * mode,FILE * stream)

函数传入值

path:文件路径全称

mode: 参见文件处理方式

stream:原先打开的文件流

函数返回值

成功:文件顺利打开后,指向该流的文件指针就会被返回

错误:返回NULL,并把错误代码存在errno中

 

             fclose(关闭文件)

 

 

所需头文件

#include <stdio.h>

函数说明

fclose()用来关闭先前fopen()打开的文件。此动作会让缓冲区内的数据写入文件中,并释放系统所提供的文件资源

函数原型

int fclose(FILE * stream)

函数传入值

stream:文件指针

函数返回值

成功:0

出错:返回EOF,并把错误代码存到errno

 

                   fileno(返回文件流所使用的文件描述符)

 

 

所需头文件

#include <stdio.h>

函数说明

fileno()用来取得参数stream指定的文件流所使用的文件描述符

函数原型

int fileno(FILE * stream)

函数传入值

stream:已打开的文件指针

函数返回值

返回文件描述符

 

(2) 打开关闭函数举例

fopen.c源代码如下:

#include <stdio.h>

int main()

{

    FILE * fp;

    int fd ;

    fp=fopen("noexist","a+");

    if(fp==NULL)

    {

            perror("fopen error") ;

            return;

    }

 

    fd = fileno( fp ) ;

    printf("fildes no=%d\n", fd ) ;

    fclose(fp);

 

    return 0 ;

}

编译 gcc fopen.c -o fopen。

执行 ./fopen,执行结果如下:

fildes no=3

 

fdopen.c源代码如下:

#include <stdio.h>

int main()

{

    FILE *fp =fdopen(0,"w+");

    fprintf(fp,"%s\n","hello!");

    fclose(fp);

    return 0 ;

}

编译 gcc fdopen.c -o fdopen。

执行 ./fdopen,执行结果如下:

hello!

 

freopen.c源代码如下:

#include <stdio.h>

int main()

{

    FILE * fp;

    fp=fopen("/etc/passwd","r");

    if ( NULL == fp )

    {

        perror("fopen error") ;

        return -1;

    }

    printf("first fildes no=%d\n", fileno(fp)) ;

    fp=freopen("/etc/group","r",fp);

    if ( NULL == fp )

    {

        perror("fopen error") ;

        return -1;

    }

    printf("second fildes no=%d\n", fileno(fp)) ;

    fclose(fp);

    return 0 ;

}

编译 gcc freopen.c -o freopen。

执行 ./freopen,执行结果如下:

first fildes no=3

second fildes no=3

可见freopen是先关闭文件描述符,然后重新打开文件描述符。

2.   以字符串为单位的I/O函数

(1) 函数原型

             fgets(从文件中读取一字符串)

 

 

所需头文件

#include <stdio.h>

函数说明

用来从参数stream所指的文件内读入字符并存到参数s所指的内存空间,直到出现换行字符、读到文件尾或是已读了size-1个字符为止,最后会加上NULL作为字符串结束

函数原型

char * fgets(char * s,int size,FILE * stream)

函数传入值

s:读取内容存放字符串地址

size:所读的最大长度

stream:文件指针

函数返回值

成功:返回s的指针

出错:返回NULL

 

             fputs(将一指定的字符串写入文件内)

 

 

所需头文件

#include <stdio.h>

函数说明

用来将参数s所指的字符串写入到参数stream所指的文件内

函数原型

int fputs(const char * s,FILE * stream)

函数传入值

s:读取内容存放字符串地址

stream:文件指针

函数返回值

成功:返回写出的字符个数

出错:返回EOF则表示有错误发生

 

(2) 函数举例

fgets.c源代码如下:

#include <stdio.h>

int main()

{

    char s[80];

    fputs(fgets(s,80,stdin),stdout);

    return 0 ;

}

编译 gcc fgets.c -o fgets。

执行 ./fgets,执行结果如下:

this is a test /*输入*/

this is a test /*输出*/

3.   以块为单位的I/O函数

(1) 函数原型

              fread(从文件流读取数据)

 

 

所需头文件

#include <stdio.h>

函数说明

用来从文件流中读取数据,读取的字符数由参数size*nmemb来决定。fread()会返回实际读取到的nmemb数目,如果此值比参数nmemb小,则代表可能读到了文件尾或有错误发生,这时必须用feof()或ferror()来决定发生什么情况

函数原型

size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream)

函数传入值

ptr:指向欲存放读取进来的数据空间

size:读取单个块长度

nmemb:读取的块数

stream: 已打开的文件指针

函数返回值

实际读取到的nmemb数目

 

               fwrite(将数据写至文件流)

 

 

所需头文件

#include <stdio.h>

函数说明

用来将数据写入文件流中。总共写入的字符数由参数size*nmemb来决定。fwrite()会返回实际写入的nmemb数目

函数原型

size_t fwrite(const void * ptr,size_t size,size_t nmemb,FILE * stream)

函数传入值

ptr:指向欲写入的数据地址

size:写入单个块长度

nmemb:写入的块数

stream:已打开的文件指针

函数返回值

实际写入的nmemb数目

 

(2) 函数举例

fwrite.c源代码如下:

#include <stdio.h>

struct record {

    char name[10];

    int age;

};

int main(void)

{

    struct record array[2] = {{"Ken", 24}, {"Knuth", 28}};

    FILE *fp = fopen("recfile", "w");

    if (fp == NULL) {

        perror("Open file recfile");

        return -1;

    }

   /*变量在内存中为对齐存放,整型占4个字节,所以整型变量要存放在能除断4的内存地址上*/

    printf("record length=%d\n", sizeof( struct record )) ;

    printf("record name =%d, address=%d\n", sizeof(array[0].name), &array[0].name) ;

    printf("record age=%d, address=%d\n ", sizeof(array[0].age), &array[0].age) ;

    fwrite(array, sizeof(struct record), 2, fp);

    fclose(fp);

    return 0;

}

编译 gcc fwrite.c -o fwrite。

执行 ./fwrite,执行结果如下:

record length=16

record name =10, address=-1081549780

record age=4, address=-1081549768

 

fread.c源代码如下:

#include <stdio.h>

struct record {

    char name[10];

    int age;

};

int main(void)

{

    struct record array[2];

    FILE *fp = fopen("recfile", "r");

    if (fp == NULL) {

        perror("Open file recfile");

        return -1;

    }

    fread(array, sizeof(struct record), 2, fp);

    printf("Name1: %s\tAge1: %d\n", array[0].name, array[0].age);

    printf("Name2: %s\tAge2: %d\n", array[1].name, array[1].age);

    fclose(fp);

    return 0;

}

编译 gcc fread.c -o fread。

执行 ./fread,执行结果如下:

Name1: Ken      Age1: 24

Name2: Knuth    Age2: 28

4.   以字节为单位的I/O函数

(1) 函数原型

                fputc(将一指定字符写入文件流中)

 

 

所需头文件

#include <stdio.h>

函数说明

将参数c 转为unsigned char 后写入参数stream 指定的文件中

函数原型

int fputc(int c, FILE * stream)

函数传入值

c:写入成功的字符

stream:已打开的文件指针

函数返回值

成功:写入的字符,即参数c

错误:返回EOF(-1)则代表写入失败

附加说明

putc原型同fputc,其作用也相同,但putc()为宏定义,非真正的函数调用

 

                fgetc(将从文件中读取一个字符)

 

 

所需头文件

#include <stdio.h>

函数说明

从参数stream所指的文件中读取一个字符。若读到文件尾无数据时便返回EOF

函数原型

int fputc(FILE * stream)

函数传入值

stream:已打开的文件指针

函数返回值

成功:返回读到的字符

错误:返回EOF(-1)则代表读取失败

附加说明

getc原型同fgetc,其作用也相同,但getc()为宏定义,非真正的函数调用

 

               getchar(从标准输入设备内读取一个字符)

 

 

所需头文件

#include <stdio.h>

函数说明

getchar()用来从标准输入设备中读取一个字符。然后将该字符从unsigned char转换成int后返回

函数原型

int getchar(void)

函数返回值

getchar()会返回读取到的字符,若返回EOF,则表示有错误发生

 

               putchar(将指定的字符写到标准输出设备)

 

 

所需头文件

#include <stdio.h>

函数说明

putchar()用来将参数c字符写到标准输出设备

函数原型

int putchar (int c)

函数返回值

putchar()会返回输出成功的字符,即参数c。若返回EOF,则代表输出失败

附加说明

putchar()函数是通过putc(c,stdout)的宏定义实现的

 

(2) 函数举例

fgetc.c源代码如下:

#include <stdio.h>

int main()

{

    FILE *fp;

    FILE *fp1;

    int c;

    fp=fopen("exist.txt","r");

    if ( NULL == fp )

    {

        perror("fopen error") ;

        return -1;

    }

    fp1= fopen("noexist.txt","w");

    if ( NULL == fp1 )

    {

        perror("fopen error") ;

        return -1;

    }

    while((c=fgetc(fp))!=EOF)

    {

        fputc(c, fp1) ;

    }

    fclose(fp);

    fclose(fp1);

    return 0 ;

}

编译 gcc fgetc.c -o fgetc。

创建exist.txt文件并输入内容,执行./fgetc。查看结果发现产生了noexist.txt,且两文件内容一样。

5.   操作读写位置的函数

(1) 函数原型

                fseek(移动文件流的读写位置)

 

 

所需头文件

#include <stdio.h>

函数说明

用来移动文件流的读写位置。参数offset为根据参数whence来移动读写位置的位移数

函数原型

int fseek(FILE * stream,long offset,int whence)

函数传入值

stream:已打开的文件指针

offset:根据参数whence来移动读写位置的位移数,可为正、负、0

          whence(既可以用宏,也可以用数字)

起始点

宏表示符号

数字表示

文件首

SEEK_SET

0

当前位置

SEEK_CUR

1

文件末尾

SEEK_END

2

函数返回值

成功:0

错误:-1,errno会存放错误代码

常见使用方法

①        欲将读写位置移动到文件开头时用fseek(FILE *stream,0,SEEK_SET)

②        欲将读写位置移动到文件尾时用fseek(FILE *stream,0,0SEEK_END)

 

                 rewind(重设文件流的读写位置为文件开头)

 

 

所需头文件

#include <stdio.h>

函数说明

rewind()用来把文件流的读写位置移至文件开头。参数stream为已打开的文件指针,此函数相当于调用fseek(stream,0,SEEK_SET)

函数原型

void rewind(FILE * stream)

函数传入值

stream:已打开的文件指针

 

                 ftell(取得文件流的读取位置)

 

 

所需头文件

#include <stdio.h>

函数说明

ftell()用来取得文件流目前的读写位置

函数原型

long ftell(FILE * stream)

函数传入值

stream:已打开的文件指针

函数返回值

成功:目前的读写位置

错误:-1,errno会存放错误代码

错误代码

EBADF:参数stream无效或文件流的读写位置无效

 

                  feof(检查文件流是否读到了文件尾)

 

 

所需头文件

#include <stdio.h>

函数说明

用来侦测是否读取到了文件尾。如果已到文件尾,则返回非零值,其他情况返回0

函数原型

int feof(FILE * stream)

函数传入值

stream:已打开的文件指针

函数返回值

返回非零值代表已到达文件尾

 

(2) 函数举例

fseek.c源代码如下:

#include <stdio.h>

int main()

{

    FILE * stream;

    long offset;

    stream=fopen("/etc/passwd","r");

    fseek(stream,5,SEEK_SET);

    printf("offset=%d\n",ftell(stream));

    rewind(stream);

    printf("offset = %d\n",ftell(stream));

    printf("file eof status=%d\n", feof(stream)) ;

    fseek(stream,0,SEEK_END);

    printf("offset = %d\n",ftell(stream));

    printf("eof=%d\n", fgetc(stream)) ;

    printf("file eof status=%d\n", feof(stream)) ;

    fclose(stream);

    return 0 ;

}

编译 gcc fseek.c -o fseek。

执行 ./fseek,结果如下:

offset=5

offset = 0

file eof status=0

offset = 2676

eof=-1

file eof status=1

 

ftell.c源代码如下:

#include <stdio.h>

int main()

{

    FILE *fp;

    long flen;

    char data[10000] ;

    if( ( fp = fopen( "/etc/passwd" , "r" ) ) == NULL ){

         perror("fopen error") ;

        return -1 ;

    }

    fseek(fp,0L,SEEK_END); /* 定位到文件末尾 */

    flen=ftell(fp); /* 得到文件大小 */

    fseek(fp,0L,SEEK_SET); /* 定位到文件末尾 */

    fread(data,flen,1,fp); /* 一次性读取全部文件的内容 */

    fclose(fp);

    printf("passwd file content:\n%s\n", data ) ;

    return 0 ;

}

编译 gcc ftell.c -o ftell。

执行 ./ftell,执行结果如下:

passwd file content:

root:x:0:0:root:/root:/bin/bash

daemon:x:1:1:daemon:/usr/sbin:/bin/sh

......

6.   格式化读写函数

(1) 函数原型

                    fprintf(格式化输出数据至文件)

 

 

所需头文件

#include <stdio.h>

函数说明

fprintf()会根据参数format字符串来转换并格式化数据,然后将结果输出到参数stream指定的文件中,直到出现字符串结束('\0')为止

函数原型

int fprintf(FILE * stream, const char * format, ...)

函数传入值

stream:文件描述符

format:格式项

函数返回值

成功:返回实际输出的字节数

失败:-1,并把错误代码存在于errno中

 

                    fscanf(格式化字符串输入)

 

 

所需头文件

#include <stdio.h>

函数说明

fscanf()会从参数stream的文件流中读取字符串,再根据参数format字符串来转换并格式化数据。格式化转换形式请参考scanf()。转换后的结构存于对应的参数内

函数原型

int fscanf(FILE * stream, const char *format, ...)

函数传入值

stream:文件描述符

format:格式项

函数返回值

成功:返回参数数目

失败:-1,并把错误代码存在于errno中

 

(2) 函数举例

fprintf.c源代码如下:

#include <stdio.h>

int main()

{

    int i = 150;

    int j = -100;

    double k = 3.14159;

    int fp ;

    fp = fprintf(stdout,"%d %f %x \n",j,k,i);

    fp = fprintf(stdout,"%2d %*d\n",i,2,i);

    printf(" fp=%d\n", fp) ;

    return 0 ;

}

编译 gcc fprintf.c -o fprintf。

执行 ./fprintf,执行结果如下:

-100 3.141590 96

150 150

fp=8

 

fscanf.c源代码如下:

#include<stdio.h>

int main()

{

    int i;

    unsigned int j;

    char s[5];

    int fd ;

    fd =fscanf(stdin,"%d %x %5[a-z] %*s %f",&i,&j,s,s);

    printf("%d %d %s \n",i,j,s);

    printf("fd=%d\n", fd) ;

    return 0 ;

}

编译 gcc fscanf.c -o fscanf。

执行 ./fscanf,执行结果如下:

10 0x1b aaaaaaaaa bbbbbbbbbb /*从键盘输入*/
10 27 aaaaa

fd=3

7.   产生临时文件

mktemp函数只产生唯一的临时文件名,并不产生临时文件,而且存在安全隐患,不建议使用。mkstemp函数会产生唯一的临时文件。

(1) 函数原型

                   mktemp(产生唯一的临时文件名)

 

 

所需头文件

#include <stdlib.h>

函数说明

mktemp()用来产生唯一的临时文件名,并不创建文件。参数template所指的文件名称字符串中最后六个字符必须是XXXXXX,产生后的文件名会借字符串指针返回

函数原型

char * mktemp(char * template)

函数传入值

template:所指的文件名称字符串,最后六个字符必须是XXXXXX

函数返回值

成功:以指针方式返回产生的文件名

失败:NULL,并把错误代码存于errno中

附加说明

参数template所指的文件名称字符串必须声明为数组,如:

char template[ ]= "template-XXXXXX";

不可用char * template="template-XXXXXX";

 

                    mkstemp(建立唯一的临时文件)

 

 

所需头文件

#include <stdlib.h>

函数说明

mkstemp()用来建立唯一的临时文件。参数template 所指的文件名称字符串中最后六个字符必须是XXXXXX。mkstemp()会以可读写模式来打开该文件,如果该文件不存在则会建立该文件。

函数原型

int mkstemp(char * template)

函数传入值

template:所指的文件名称字符串,最后六个字符必须是XXXXXX

函数返回值

成功:文件顺利打开后,返回该文件的文件描述符

失败:如果文件打开失败,则返回0,并把错误代码存于errno中

附加说明

参数template所指的文件名称字符串必须声明为数组,如:

char template[ ]= "template-XXXXXX";

不可用char * template="template-XXXXXX";

 

(2) 函数举例

mktemp.c源代码如下:

#include <stdio.h>

int main()

{

    char template[ ]="template-XXXXXX";

    char *file ;

    file = mktemp(template);

    printf("template=%s\n",template);

    printf("file=%s\n", file);

    return 0 ;

}

编译 gcc mktemp.c -o mktemp。

执行 ./mktemp,执行结果如下:

template=template-oh2jT8

file=template-oh2jT8

 

mkstemp.c源代码如下:

#include <stdio.h>

int main()

{

    int fd;

    char template[ ]="template-XXXXXX";

    fd=mkstemp(template);

    printf("template = %s\n",template);

    printf("fd = %d\n", fd);

    close(fd);

    return 0 ;

}

编译 gcc mkstemp.c -o mkstemp。

执行 ./mkstemp,执行结果如下:

template = template-rPGs2W

fd = 3

8.   错误检测与清除

(1) 函数原型

                   ferror(检查文件流是否有错误发生)

 

 

所需头文件

#include <stdio.h>

函数说明

ferror()用来检查参数stream所指定的文件流是否发生了错误情况,如有错误发生则返回非0值

函数原型

int ferror(FILE *stream)

函数传入值

stream:已打开的文件指针

函数返回值

如果文件流有错误发生则返回非0值

 

                    clearerr(清除文件流的错误标记)

 

 

所需头文件

#include <stdio.h>

函数说明

clearerr()清除参数stream指定的文件流所使用的错误标记

函数原型

void clearerr(FILE * stream)

函数传入值

stream:已打开的文件指针

函数返回值

9.   文件编程综合实例

源代码file.c如下:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

 /*去掉字符串左边指定字符*/

char *LTrimChar( char *pBuf, char cDel )

{

    char *pTmp = pBuf ;

    if ( ( cDel != '\0' ) && ( pTmp != NULL ) )

    {

        while ( *pTmp++ ==  cDel ) ;

        strcpy( pBuf, pTmp - 1 );

    }

    return pBuf ;

}

/*去掉字符串右边指定字符*/

char *RTrimChar( char *pBuf, char cDel )

{

    char *pTmp = pBuf;

    if ( ( cDel != '\0' ) && ( pTmp != NULL ) )

    {

        for ( pTmp = pBuf + strlen( pBuf ) -1 ;

                ( *pTmp ==  cDel ) && ( pTmp >= pBuf ) ; *pTmp--  = '\0' );

    }

    return pBuf ;

 

}

/*去掉字符串两边指定字符*/

char *AllTrimChar( char *pBuf, char cDel )

{

    return  LTrimChar( RTrimChar( pBuf, cDel  ) , cDel );

}

int main(int argc, char **argv)

{

    char buff_read[128];

    long line_length ;

    char seri_no[8+1];

    char cust_acct_no[22+1] ;

    char amt[17+1] ;  /*原文件金额除以100进行转换*/

    char *ptr;

    FILE *fpr; /*读文件指针*/       

    FILE *fpw; /*写文件指针*/        

    char file_read[64];

    char file_write[64];

    sprintf( file_read,"%s", "read.txt" );

    if( ( fpr = fopen( file_read,"r" ) ) == NULL  ) {           

        perror("fopen error\n");

        return -1;

    }   

    strcpy( file_write, "write.txt") ;

    fpw = fopen( file_write , "w" );

    if( fpw == NULL )  {      

        perror("fopen error\n");

        return -1;

    } 

    memset( buff_read , 0x00 , sizeof( buff_read ));

    line_length= sizeof(buff_read) ;

    while( fgets( buff_read, line_length, fpr ) != NULL ) {      

        memset(seri_no, 0x00, sizeof(seri_no)) ;

        memset(cust_acct_no, 0x00, sizeof(cust_acct_no)) ;

        memset(amt, 0x00, sizeof(amt)) ;

        memcpy( seri_no , buff_read+0 , 8 );

        AllTrimChar( seri_no, ' ' ) ; /*去掉两边的空格*/

        memcpy( cust_acct_no , buff_read+8 , 22 );

        AllTrimChar( cust_acct_no, ' ' ) ;

        memcpy( amt , buff_read+30 , 17 );

        AllTrimChar( amt, ' ' ) ;

        fprintf(fpw,"%-8.8s%-22.22s%-17.2lf\n", seri_no,cust_acct_no, atof(amt)/100 ) ;

    }

    fclose( fpr );

    fclose( fpw );

    return 0 ;

}

编译 gcc file.c –o file。

read.txt文件内容为:

123456  12345678909876543210  1234567         

123457  12345678909876543230  1234565         

执行 ./file。发现建立了write.txt文件,其文件内容为:

123456  12345678909876543210  12345.67

123457  12345678909876543230  12345.65

 

摘录自《深入浅出Linux工具与编程》

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值