标准I\O的机理,二进制模式和文本模式,文件输入,输出中需要的各种函数

putc函数:第一个参数是待写入的字符,第二个参数是文件指针,putc(ch,stdout)与putchar(ch)相同

而ch = getc(fp)是指从getc指定的文件fp中获取一个字符给ch

fputs是一种函数,具有的功能是向指定的文件写入一个字符串。成功写入一个字符串后,文件的位置指针会自动后移,函数返回为一个非负整数;否则返回EOF(符号常量,其值为-1)。

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

fgets(buf,strlen,fp),buf是char类型数组的名称,strlen是字符串的大小,fp是指向FILE的指针 ,需要注意的是fgets()在字符串中保留换行符

该函数读取输入的特点:>fgets()函数读取输入直到第一个换行符的后面,或读到文件结尾,或者读取strlen-1个字符,然后fgets()在末尾添加一个空字符使之成为一个字符串。字符串的大小是其字符加上一个空字符。


随机访问:fseek()与ftell()

有了fseek函数,就可以把文件看作是数组,在fopen()打开的文件中直接移动到任意字节处。
fseek()有3个参数,第一个参数是FILE指针,指向待查找的文件。 注意此时fopen()应该已打开该文件
第二个参数是偏移量,该参数表示从起始点开始要移动的距离。该参数必须是一个long类型,可为正(前移),负(后移)或不动)
第三个参数是模式,该参数确定起始点。根据ANSI标准,在stdio.h头文件中规定了几个表示模式的明示常量:

SEEK_SET: 文件开始处
SEEK_CUR: 当前位置
SEEK_END: 文件末尾
旧的实现可能缺少这些定义,可以使用数值0L,1L,2L分别表示这三种模式。L后缀表示其是long类型。
以下是调用fseek()函数的一些实例,fp是一个文件指针:

fseek(fp,0L,SEEK_SET)  //定义至文件开始处
fseek(fp,10L,SEEK_SET) //定位至文件中的第10个字节
fseek(fp,2L,SEEK_CUR)  //从文件当前位置前移两个字节
fseek(fp,0L,SEEK_END)  //定位至文件结尾
fseek(fp,-10L,SEEK_END) //从文件结尾处回退10个字节

fseek(fp,0L,SEEK_END)还有一种解释就是:把当前位置设置为距文件末尾0字节偏移量。也就是说,该语句把当前位置设置在文件结尾。也可以说该函数的起点为文件结尾处。
last = ftell(fp): 把从文件开始处到文件结尾的字节数赋给last

for ( count = 1L; coutn <= last; count++ )
{
    fseek(fp, -count, SEEK_END);
    ch = getc(fp);
    //第一轮迭代,把程序定位到文件结尾的第一个字符(即文件的最后一个字符)。然后,程序打印该字符。下一轮迭代把程序定位到前一个字符,并打印该字符。重复这个过程直至达到文件的第一个字符,并打印。
}

如果一切正常,fseek()的返回值为0,如果出现错误,其返回值为-1
ftell()函数返回一个long类型的值,它返回的参数指向文件的当前位置距文件开始出的字节数。
ANSI C规定,该定义适合用于以二进制模式打开的文件,以文件模式打开文件的情况不同。这也是下面的程序用二进制打开文件的原因。


下面演示ftell()与fseek()的用法:

#include <stdio.h>
#include <stdlib.h>
#define CNTL_Z  '0\O32'   //DOS文本文件中的文件结尾标记
#define SLEN 81
int main(void)
{
    char file[SLEN];
    char ch;
    FILE *fp;
    long count,last;
    puts("Enter the name of the file to be processed:");
    scanf("%80s",file);
    if ( (fp =fopen(file,"rb")) == NULL )
    {
        printf("reverse can not open %s\n",file);
        exit(EXIT_FAILURE);
    }
    fseek(fp,0L,SEEK_END); // 定位到文件末尾
    last = ftell(fp);
    for ( count = 1L; count <= last; count++ )
    {
        fseek(fp,--count,SEEK_END);
        ch = getc(fp);
        if ( ch != CNTL_Z && ch != '\r' )
        {
            putchar(ch);
        }
    }
    putchar('\n');
    fclose(fp);
    return 0;
}

fwrite与fread函数

fwrite:以二进制格式把数组写入文件

fgetpos()和fsetpos()函数

这两个函数不使用long类型表示位置,他们使用一个新类型:fpos_t.它不是基本类型,需要根据其他类型来定义。fpos_t不能是数组类型,但可以实现结构。
fgetops()函数原型如下:

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()获得
接下来,用一个程序实例把一系列文件中的内容附加在另一个文件的末尾。通过交互式的方法给文件传递信息:
在C语言中static的作用如下
第一、在修饰变量的时候,static修饰的静态局部变量只执行一次,而且延长了局部变量的生命周期,直到程序运行结束以后才释放。
第二、static修饰全局变量的时候,这个全局变量只能在本文件中访问,不能在其它文件中访问,即便是extern外部声明也不可以。
第三、static修饰一个函数,则这个函数的只能在本文件中调用,不能被其他文件调用。Static修饰的局部变量存放在全局数据区的静态变量区。初始化的时候自动初始化为0;
(1)不想被释放的时候,可以使用static修饰。比如修饰函数中存放在栈空间的数组。如果不想让这个数组在函数调用结束释放可以使用static修饰
(2)考虑到数据安全性(当程序想要使用全局变量的时候应该先考虑使用static)


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFSIZE 4096
#define SLEN 81
void append(FILE *source, FILE *dest)
{
    size_t bytes;
    static char temp[BUFSIZE];//只分配一次
    while ( (bytes = fread(temp, sizeof(char), BUFSIZE, source) ) > 0 )//fread返回成功读取项的数量
    {
        fwrite(temp, sizeof(char), bytes, dest);
    }
}
char *s_gets(char *st, int n)
{
    char * ret_val;
    char * find;
    ret_val = fgets(st, n, stdin);
    while (ret_val != NULL )
    {
        find = strchr(st,'\n');
        if ( find ){
            *find = '\0';
        }
        else{
            while (getchar() != '\n')
            {
                continue;
            }
        }
    }
    return ret_val;
}
int main()
{
    FILE *fa, *fs; // fa 指向目标文件,fs指向源文件
    int files = 0;//附加文件数量
    char file_app[SLEN];  //目标文件名
    char file_src[SLEN];  //正在处理的文件名
    int ch;//输入文件内容
    puts("enter name of destination file:");
    s_gets(file_app,SLEN); //以更新模式打开文件(即读和写),在现有文件的末尾添加内容,如果文件不存在则创建一个新文件;可以读整个文件,但是只能从末尾添加内容
    if ( (fa = fopen(file_app,"a+") == NULL ){
        fprintf(stderr,"can not open %s\n",file_app);
        exit(EXIT_FALIURE);
    }
    if ( setvbuf(fa, NULL, _IOFBF, BUFSIZE) != 0 )//创建一个临时缓冲区将第二个参数设置为NULL时,该函数会为自己分配一个缓冲区,BUFSIZE告诉setvbuf()数组的大小,操作成功,则返回0
    {
        fputs("can not create output buffer\n",stderr);
        exit(EXIT_FAILURE);
    }
    puts("enter name of first source file:");
    while (s_gets(file_src, SLEN) && filefile_src[0] != '\0')
    {
        if ( strcmp(file_src, file_app) == 0 ){
            fputs("can not open files\n",stderr);
            exit(EXIT_FAILURE);
        }else if( (fs = fopen(file_src,"r")) == NULL ){
            fprintf(stderr,"can not open %s",file_src);
        }else{
            if (setvbuf(fs, NULL, _IOFBF, BUFSIZE) != 0){
                fputs("can not create input buffer\n", stderr);
                continue;
            }
            append(fs, fa);
            if (ferror(fs) != 0){
                fprintf(stderr,"error in writing file %s\n",file_src);
            }
            if (ferror(fs) != 0){
                fprintf(stderr,"error in writing file %s\n",file_src);
            }
            fclose(fs);
            files++;
            printf("file %s appended\n", file_src);
            puts("next file:");
        }
    }
    printf("done appending.%d files appended\n",files);
    rewind(fa);原型:void rewind(FILE *fp)   作用:使文件fp的位置指针指向文件开始。
    printf("%s contents:\n",file_app);
    while ((ch = getc(fa) != EOF )
    {
        putchar(ch);
    }
    puts("done displaying.");
    fclose(fa);
    return 0;
}

用二进制I/O随机访问:如下所示的程序创建了一个储存在double类型数字的文件,然后让用户访问这些内容。

#include <stdio.h>
#include <stdlib.h>
#define ARSIZE 1000
int main()
{
    double numbers[ARSIZE];
    double value;
    const char * file = "numbers.dat";
    int i;
    long pos;
    FILE *iofile;
    //创建一组double类型的值:
    for ( i = 0; i < ARSIZE; i++ )
    {
        numbers[i] = 100.0 * i + 1.0/(i+1);
    }
    //尝试打开文件
    if ( (iofile = fopen(file,"wb") ) == NULL )//以二进制模式打开文件
    {
        fprintf(stderr,"can not open %s\n",file);
        exit(EXIT_FAILURE);
    }
    fwrite(numbers,sizeof(double),ARSIZE,iofile);
    fclose(iofile);
    if ( (iofile = fopen(file,"rb") == NULL )
    {
        fprintf(stderr,"can not open %s\n",file);
        exit(EXIT_FAILURE);
    }
    //从文件中读取选定内容
    printf("enter an index in the range 0-%d\n",ARSIZE-1);
    while( scanf("%d",&i) == 1 && i >= 0 && i < ARSIZE )
    {
        pos = (long) i * sizeof(double);//计算偏移量
        fseek(iofile, pos, SEEK_SET);//定位到此处
        fread(&value,sizeof(double),1,iofile);
        printf("the value there is %f\n",value);
        printf("next index:\n");
    }
    fclose(iofile);
    puts("bye");
    return 0;
}

小结

1.如果要在不损失精度的前提下保存或恢复数值数据,请使用二进制模式以及fread()和fwrite()函数。
2.如果打算保存文本信息并床架能在普通文本编译器查看的文本,请使用文本模式和函数(如getc()何fprintf())
3.要访问文件,必须创建文件指针(类型是FILE )并把指针和特定文件名相关联。随后的代码就可以使用这个指针(而不是文件名)来处理文件.

猜你喜欢

转载自blog.csdn.net/teropk/article/details/79896236
今日推荐