C语言常见文件操作

在C语言中主要通过标准的I/O函数来对文本文件进行操作。常见的文本操作函数包括
fopen()(打开) fclose()(关闭) fgetc()(读取字符) fputs()(写入字符) fprintf()(写入) fscanf()(读取)

1.打开文件

函数原型:

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

其中:
path :文件完整路径(如果没有指定路径,则默认为当前工作目录)
mode :为指定的打开模式

如果打开成功,fopen会返回一个结构指针地址,否则返回一个NULL。

FILE *fp;
fp = fopen("c:\\temp\\test.txt", "r")

使用fopen()函数打开的文件会先将文件复制到缓冲区。注意:所下达的读取或写入动作,都是针对缓冲区进行存取而不是磁盘,只有当使用fclose()函数关闭文件时,缓冲区中的数据才会写入磁盘。

1.1打开模式:

“r”:只能从文件中读数据,该文件必须先存在,否则打开失败
“w”:只能向文件写数据,若指定的文件不存在则创建它,如果存在则先删除它再重建一个新文件
“a”:向文件增加新数据(不删除原有数据),若文件不存在则会建立该文件
“r+”:可读/写数据,该文件必须先存在,否则打开失败
“w+”:可读/写数据,用该模式打开新建一个文件,先向该文件写数据,然后可读取该文件中的数据
“a+”:可读/写数据,原来的文件不被删去,位置指针移到文件末尾

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

2.关闭文件:

函数原型:

int fclose( FILE *fp );

返回值:如果流成功关闭,fclose 返回 0,否则返回EOF(-1)。(如果流为NULL,而且程序可以继续执行,fclose设定error number给EINVAL,并返回EOF。)

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

FILE *fp;
fp = fopen("c:\\temp\\test.txt", "r");

if(fp == NULL)
    printf("fail to open the file! \n");
else
{
    printf("The file is open! \n");
    fclose(fp);
}

3.字符存取函数

函数原型为:

int fputc (char c, File *fp)
int fgetc(FILE *stream);

字符读取函数fgetc()可从文件数据流中一次读取一个字符,然后读取光标移动到下一个字符,并逐步将文件的内容读出。

如果字符读取成功,则返回所读取的字符,否则返回EOF(end of file)。EOF是表示数据结尾的常量,真值为-1。另外,要判断文件是否读取完毕,可利用feof()进行检查。未完返回0,已完返回非零值。

feof()函数原型为:

int feof(FILE *stream);
#include <stdio.h>

main()
{
    FILE *fp;
    fp = fopen("c:\\temp\\test.txt", "r");
    if(fp != NULL)
    {
        while(!feof(fp))
            printf("%c", fgetc(fp));
    }
    else
        printf("fail to open! \n");
    fclose(fp);

    return 0;
}

若要将字符逐一写入文件,用fputc()函数。

示例为:

#include <stdio.h>
#include <conio.h>

main()
{
    char filename[20], ch;
    FILE *fp;
    printf("Enter a filename: ");
    scanf("%s", filename);
    printf("Enter some characters to output to file: ");
    if((fp = fopen(filename, "w")) == NULL)
        printf("fail to open! \n");
    else
    {
        while((ch = getche()) != '\015')
            fputc(ch, fp);
    }
    fclose(fp);

    return 0;
}

4.字符串存取函数

函数原型为:

 int  fputs(const char *, FILE *);
char *  fgets(char *, int, FILE *);

fgets函数的作用是从指定文件读入一个字符串,如:fgets(str, n, fp);

参数n为要求得到的字符个数,但只从fp指向的文件输入n-1个字符,然后在最后加一个’\0’字符,因此得到的字符串共有n个字符,把它们放在字符数组str中。如果在读完n-1个字符之前遇到换行符或EOF,读入结束。

fputs函数的作用是向指定文件输出一个字符串,如:fputs(“Hey”, fp);

把字符串”Hey”输出到fp指向的文件。fputs函数的第一个参数可以是字符串常量、字符数组名或字符型指针。若输出成功,则返回0,否则返回EOF。
2.5 格式化存取函数
函数原型为:

 int  fprintf(FILE *, const char *, ...);
 int  fscanf(FILE *, const char *, ...);

它们与printf和scanf函数相仿,都是格式化读写函数。不同的是:fprintf和fscanf函数的读写对象不是终端(标准输入输出),而是磁盘文件。printf函数是将内容输出到终端(屏幕),因此,fprintf就是将内容输出到磁盘文件了。

#include <stdio.h>

void main()
{
    FILE *fp;

    int num = 10;
    char name[10] = "Leeming";
    char gender = 'M';

    if((fp = fopen("info.txt", "w+")) == NULL)
        printf("can't open the file! \n");
    else
        fprintf(fp, "%d, %s, %c", num, name, gender); //将数据格式化输出到文件info.txt中

    fscanf(fp, "%d, %s, %c", &num, name, &gender); //从文件info.txt中格式化读取数据
    printf("%d, %s, %c \n", num, name, gender); //格式化输出到屏幕

    fclose(fp);
}

5. 指针重返函数

函数原型为:

 void  rewind(FILE *);

rewind函数的作用是使位置指针重返回文件的开头,属于文件的定位。

6.二进制文件操作

6.1 数据块存取函数

函数原型:

 size_t  fread(void *, size_t, size_t, FILE *);
 size_t  fwrite(const void *, size_t, size_t, FILE *);

当要求一次存取一组数据(如,一个数组、一个结构体变量的值),fread和fwrite函数可以解决该类问题。它们的调用形式一般为:

fread(buffer, size, count, fp);
fwrite(buffer, size, count, fp);

buffer:对于fread来说,指的是读入数据的存放地址;对于fwrite来说,是要输出数据的地址。
size:读写数据时,每笔数据的大小
count:读写数据的笔数
fp:文件指针

#include <stdio.h>
#define SIZE 3

typedef enum { MM, GG } Gender;

typedef struct
{
    char name[10];
    int  age;
    Gender gender;
} Person;

void write2file(Person emp[SIZE])
{
    FILE *fp;
    if((fp = fopen("emp.txt", "wb")) == NULL)
    {
        printf("cannot open file! \n");
        return;
    }

    for(int i=0; i<SIZE; i++)
        if(fwrite(&emp[i], sizeof(Person), 1, fp) != 1)
            printf("file write error! \n");
    fclose(fp);
}

void read_from_file(FILE *fp)
{
    Person emp_out[SIZE];

    if((fp = fopen("emp.txt", "rb")) == NULL)
    {
        printf("cannot open file! \n");
        return;
    }

    printf("\n%d employee's information read: \n", SIZE);

    for(int i=0; i<SIZE; i++)
    {
        if(fread(&emp_out[i], sizeof(Person), 1, fp) != 1)
            if(feof(fp))
            {
                fclose(fp);
                return;
            }
            printf("%-5s %4d %5d \n", emp_out[i].name, emp_out[i].age, emp_out[i].gender);
    }
    fclose(fp);
}

void main()
{
    FILE *fp = NULL;
    Person employee[SIZE];

    printf("Enter %d employee's information: \n", SIZE);
    for(int i=0; i<SIZE; i++)
        scanf("%s %d %d", employee[i].name, &employee[i].age, &employee[i].gender);

    write2file(employee);

    read_from_file(fp);
}

7. 随机存取函数fseek()

函数原型:

 int  fseek(FILE *, long, int);

对流式文件可以进行顺序读写,也可以进行随机读写。关键在于控制文件的位置指针,如果位置指针是按字节位置顺序移动的,就是顺序读写。如果能将位置指针按需要移动到任意位置,就可以实现随机读写。所谓随机读写,是指读完上一个字符(字节)后,并不一定要读写其后续的字符(字节),而可以读写文件中任意位置上所需要的字符(字节)。该函数的调用形式为:

fseek(fp, offset, start);

start:起始点。用0、1、2代替。0代表文件开始,名字为SEEK_SET,1代表当前位置,名字为SEEK_CUR,2代表文件末尾,名字为SEEK_END。

fseek()函数一般用于二进制文件,因为文本文件要发生字符转换,计算位置时往往会发生混乱。

调用实例如:

fseek(fp, i*sizeof(Person), 0);
posted @ 2016-04-01 22:51  lei_shitou  阅读(402)  评论(0编辑  收藏  举报