1. C语言对文件的操作

1. 文件常见输入输出函数与屏幕、键盘输入输出函数的对比,如:fprintf、fscanf等。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

void main()
{
    printf("-------------屏幕--------------\n");
    printf("锄禾日当午!\n");
    fprintf(stdout, "锄禾日当午!\n");
    //显示器当做文件来操作
    //printf就是fprintf的特例

    puts("锄禾日当午,汗滴禾下土!");    //往屏幕上输出字符串,自带换行
    fputs("锄禾日当午,汗滴禾下土!\n", stdout);//效果一样,但没有自带换行

    putchar('A');
    fputc('A', stdout);

    printf("\n-------------键盘--------------\n");

    //int num;
    //scanf("%d", &num);
    //printf("num=%d\n", num);

    //int numA;
    //fscanf(stdin,"%d", &numA);            //fscanf可以扫描任何文件,不仅是键盘
    //fprintf(stdout,"numA=%d\n", numA);

    //char str[50];
    ////gets(str);
    //fgets(str, sizeof(str) - 1, stdin);  //第二个参数需要去掉'\0'
    //fputs(str,stdout);

    char ch = fgetc(stdin);
    fputc(ch, stdout);

    system("pause");
}

 2. 标准错误输出函数stderr。

#include <stdio.h>
#include <stdlib.h>

//stderr,错误写入文件,输出错误信息
void main()
{
    //遇到错误,就可以把错误信息写入stderr,会自动在显示器上输出
    fprintf(stderr, "你遇到的错误是%s,重试次数是%d\n", "权限不够", 3);//你遇到的错误是权限不够,重试次数是 3
    //stderr始终显示在显示器,stdout如果重定向会被写入磁盘
    fprintf(stdout, "你遇到的错误是%s,重试次数是%d\n", "权限不够", 3);//你遇到的错误是权限不够,重试次数是 3

    system("pause");
}

3. 宽字符处理函数 getw 和 putw。

#include <stdio.h>
#include <stdlib.h>

void main()
{
    int W = _getw(stdin);    //从键盘获取输入,获取4个字节,最新C++需要用_getw、_putw
    _putw(W, stdout);        //显示器输出
    //可以输出两个汉字,一个汉字两个字节
    //int 用于装容两个汉字的二进制s
    //putw输出成功就返回输出的值,输出失败则返回-1

    system("pause");
}

4. 文件读写。

  读文件 (”r” 模式):

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

//"r"模式文件必须存在,不存在就打开失败
//打开成功,就可以进行读的操作
//此时进行写操作,不会提示错误,但是会操作失败
void main()
{
    char path[40] = "c:\\1.txt";
    FILE *fp = fopen(path, "r");    //"r"按照读的方式打开文件,文件必须存在,不存在则打开失败
    
    if (fp == NULL)
        printf("文件打开失败!\n");

    else
    {
        printf("文件打开成功!\n");
        
        //法一:
        while (!feof(fp))           //判断文件是否到末尾
        {
            char ch = fgetc(fp);    //从文件读取一个字符保存到ch
            putchar(ch);            //输出这个字符
        }                           //结果为:hello world!

        //上面while循环也可改为:
        //char ch = fgetc(fp);
        //while (ch != EOF)         //End Of File文件结束
        //{
        //    putchar(ch);          //输出这个字符
        //    ch = fgetc(fp);       //从文件读取一个字符保存到ch
        //}

        //还可改为do-while循环:
        //char ch;
        //do
        //{
        //    ch = fgetc(fp);
        //    putchar(ch);
        //} while (ch != EOF);

        //法二:注意对比fscanf与fgetc
        //char str[100];
        //int num;
        //while (!feof(fp))
        //{
        //    fscanf(fp, "%s", str);    //fscanf遇到空格和换行时结束
        //    printf("%s", str);        //结果为:helloworld!
        //}

        fclose(fp);                     //关闭文件指针
    }

    system("pause");
}

  写文件(”w” 模式):

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

//"w"模式:若文件不存在则建立该文件
//若文件存在则文件长度清0,即该文件内容会消失
//"w"模式只能写不能读
void main()
{
    char path[40] = "c:\\2.txt";
    FILE *fp = fopen(path, "w");    //"w"按照写的方式打开文件

    if (fp == NULL)
        printf("文件打开失败!\n");

    else
    {
        printf("文件打开成功!\n");

        fputs("hello world!\n",fp);            //向文件写入字符串
        fprintf(fp, "%s\n", "Hello World!");   //向文件写入字符串

        fclose(fp);                    //关闭文件指针
    }

    system("pause");
}

  读写文件(”r+”模式):

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

//"r+"模式文件必须存在,不存在就打开失败,存在就可以读和写
void main()
{
    char path[40] = "c:\\3.txt";
    FILE *fp = fopen(path, "r+");    //"r+"读写方式打开文件

    if (fp == NULL)
        printf("文件打开失败!\n");

    else
    {
        printf("文件打开成功!\n");

        while (!feof(fp))           //判断文件是否到末尾
        {
            char ch = fgetc(fp);    //从文件读取一个字符保存到ch
            putchar(ch);            //输出这个字符

        }

        int res = fputc('A', fp);   //写入一个字符‘A’
        if (res == -1)
            printf("\n写入失败");
        else
            printf("\n写入成功\n");

        fclose(fp);                 //关闭文件指针
    }

    system("pause");
}

  写读文件(”w+” 模式):

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

//"w+"模式:若文件不存在则建立该文件
//若文件存在则文件长度清0,即该文件内容会消失
//"w+"模式既能写也能读
void main()
{
    char path[40] = "c:\\4.txt";
    FILE *fp = fopen(path, "w+");    //写的方式打开文件

    if (fp == NULL)
        printf("文件打开失败!\n");

    else
    {
        printf("文件打开成功!\n");
        fputs("A hello world!", fp); //向文件写入字符串

        rewind(fp);                  //文件指针移动到开头
        char ch = fgetc(fp);         //从文件读取一个字符保存到ch
        //fgetc如果执行成功就会返回读取的字符;若执行失败则返回-1
        printf("%d\n", ch);
        putchar(ch);                 //输出这个字符

        fclose(fp);                  //关闭文件指针
    }

    system("pause");
}

//    w  只写模式打开,文件存在则长度清0,不存在则建立文件。
//    w+ , wb, wb+ , wt, wt+ 模式打开文件,文件不存在则建立文件

//    a  以附加的方式打开只写文件,若文件不存在,则建立文件,存在则在文件尾部添加数据
//    a+  以附加的方式打开可读写文件,不存在则建立文件,存在则写入数据到文件尾
//    at  二进制数据的追加,不存在则创建,只能写。
//    at+  读写打开一个文本文件,允许读或在文本末追加数据
//    ab  二进制数据的追加,不存在则创建,只能写。

5. access 函数:

  确定文件或文件夹的访问权限。即,检查某个文件的存取方式,比如说是只读方式、只写方式等。

  如果指定的存取方式有效,则函数返回0,否则函数返回-1。

    #define R_OK 4

    #define W_OK 2

    #define X_OK 1

    #define F_OK 0

  R_OK 只判断是否有读权限

  W_OK 只判断是否有写权限

  X_OK 判断是否有执行权限

  F_OK 只判断是否存在

#include <stdio.h>
#include <stdlib.h>
#include <io.h>    //windows在头文件<io.h>中,linux在头文件<unistd.h>中

void main()
{
    //windows下所有文件夹都是可读可写的
    //printf("%d\n", _access("c:\\1", 0));        //0 判断是否存在c:\\1这个文件夹
    
    //printf("%d\n", _access("c:\\1.txt", 0));    //0 判断是否存在c:\\1.txt这个文件
    //if (_access("c:\\1", 0))                    //存在返回0;不存在返回-1
    //    printf("文件夹不存在\n");
    //else
    //    printf("文件夹存在\n");

    //printf("%d\n", _access("c:\\1.txt", 2));    //2 判断c:\\1.txt这个文件是否可写
    //if (_access("c:\\1", 0))                    //可写返回0;不可写返回-1
    //    printf("文件不可写\n");
    //else
    //    printf("文件可写\n");

    //printf("%d\n", _access("c:\\1.txt", 4));    //4 判断c:\\1.txt这个文件是否可读
    //if (_access("c:\\1", 0))                    //可读返回0;不可读返回-1
    //    printf("文件不可读\n");
    //else
    //    printf("文件可读\n");

    printf("%d\n", _access("c:\\1.txt", 6));    //6 判断c:\\1.txt这个文件是否可读可写
    if (_access("c:\\1", 0))                    //可读可写返回0;不可读可写返回-1
        printf("文件不可读可写\n");
    else
        printf("文件可读可写\n");

    system("pause");
}

6. 按照内存块的方式读写文件(数组、结构体),fread 、 fwrite 函数:

  函数原型:

    size_t  fread(void  *buffer,size_t  size, size_t  count,FILE   *fp)

    size_t  fwrite(void  *buffer,size_t  size, size_t  count,FILE   *fp)

  功能:读/写数据块

  返值:成功,返回读/写的块数;出错或文件尾,返回0

  说明:

    typedef   unsigned   size_t;

    buffer:  指向要输入/输出数据块的首地址的指针

    size:  每个要读/写的数据块的大小(字节数)

    count:   要读/写的数据块的个数

    fp:    要读/写的文件指针

  fread与fwrite 一般用于二进制文件的输入/输出

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

//按内存块写入文件fwrite:
void main()
{
    int num[100];        //数组是连续排列的,是一段连续的内存
    for (int i = 0; i < 100; i++)
        num[i] = i;      //初始化数组

    FILE *fp;
    fp = fopen("c:\\数组.txt", "wb");    //二进制写入的模式打开文件

    if (fp == NULL)
        printf("文件打开失败\n");
    else
    {
        int res = 0;
        res = fwrite(num, sizeof(int), 100, fp);    //将内存写入文件
        //写成功多少个,会返回数量
        //第1个参数:写入内存的首地址
        //第2个参数:一个元素有多大
        //第3个参数:写多少个元素
        //第4个参数:写到哪个文件
        if (res == 100)
            printf("写入成功\n");
        else
            printf("写入失败\n");
    }

    fclose(fp);

    system("pause");
}
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

//按内存块读文件fread:
void main()
{
    int num[100];        //数组是连续排列的,是一段连续的内存

    FILE *fp;
    fp = fopen("c:\\数组.txt", "rb");    //二进制写入的模式打开文件

    if (fp == NULL)
        printf("文件打开失败\n");
    else
    {
        int res = 0;
        res = fread(num, sizeof(int), 100, fp);    //读取文件到内存
        //读成功多少个,会返回数量
        //第1个参数:读入内存的首地址
        //第2个参数:一个元素有多大
        //第3个参数:读多少个元素
        //第4个参数:读到哪个文件
        if (res == 100)
            printf("读入成功\n");
        else
            printf("读入失败\n");

        for (int i = 0; i < 100; i++)
            printf("num[%d]=%d\n", i, num[i]);    //打印数据
    }

    fclose(fp);

    system("pause");
}

7. 测试文件是否出现错误, ferror 、 perror 函数:

ferror 函数:

   在调用各种输入输出函数(如 putc.getc.fread.fwrite等)时,如果出现错误,除了函数返回值有所反映外,还可以用ferror函数检查。

  函数原型:   int  ferror(FILE  *fp)

  功能:测试文件是否出现错误

  返值:未出错,0;出错,非0

  说明

    每次调用文件输入输出函数,均产生一个新的ferror函数值,所以应及时测试

    fopen打开文件时,ferror函数初值自动置为0

 perror 函数:

   在调用各种输入输出函数时,如果出现错误,除了函数返回值有所反映外,还可以用ferror函数检查。 它的一般调用形式为 ferror(fp);如果ferror返回值为0(假),表示未出错。如果返回一个非零值,表示出错。在执行fopen函数时,ferror函数的初始值自动置为0。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

void main()
{
    char path[40] = "c:\\1.txt";
    FILE *fp = fopen(path, "r");

    if (fp == NULL)
        printf("文件打开失败!\n");

    else
    {
        printf("文件打开成功!\n");        //文件打开成功!

        //文件打开成功时,判断一次
        if (ferror(fp) == 0)
            printf("文件正常\n");        //文件正常
        else
            printf("文件出错\n");

        fputs("C语言", fp);

        //执行fputs写文件后再次判断
        if (ferror(fp) == 0)
            printf("文件正常\n");
        else
        {
            printf("文件出错\n");        //文件出错
            perror("错误原因是:");       //错误原因是:Bad file descriptor
        }    
    }

    fclose(fp);
    system("pause");
}

 8. 处理文件错误,clearerr复位错误标志:

  clearerr的作用是使文件错误标志和文件结束标志置为0.假设在调用一个输入输出函数时出现了错误,ferror函数值为一个非零值。在调用clearerr(fp)后,ferror(fp)的值变为0。

  用 法:void clearerr(FILE *stream);

#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>

//按照写的模式打开一个文件,读取会出错
void main()
{
    FILE *fp = fopen("c:\\1.txt", "w");
    
    if (fp == NULL)
    {
        printf("文件打开失败!\n");
        perror("错误信息是:");
    }
    else
    {
        fputs("hello world", fp);        //向文件输出一个字符串

        rewind(fp);                      //将文件指针移到开头

        char ch = fgetc(fp);             //从文件读取一个字符
        if (ch == EOF)                   //-1,EOF,end of file,读取文件失败返回-1,读取到最后也返回-1
        {
            if (feof(fp))                        //feof(fp)返回值为非0,到了文件末尾
            {
                printf("读到了文件末尾\n");
                clearerr(fp);                    //重置文件流的状态
            }

            if (ferror(fp))                      //ferror(fp)返回值为非0,意味着文件出错
            {
                printf("文件读取出错\n");
                clearerr(fp);                    //重置文件流的状态,清除错误信号,表明恢复正常,如果不清除下次正确的状态还会出错
            }
        }
    }

    fclose(fp);
    
    system("pause");
}

9. 文件定位函数,rewind、ftell、fseek 函数:

  文件的读写方式有两种,一是顺序读写,位置指针按字节顺序从头到尾移动,另一种是随机读写,位置指针按需要移动到任意位置,随机形式多用于二进制文件的读写。

  如果要对文件进行随机读写,就需要控制文件位置指针的值,这就是文件定位,与文件定位有关的函数是rewind函数,fseek函数和ftell函数。

  (1)rewind 函数:

    rewind函数没有返回值,其调用形式为:rewind(FILE* fp);

    该函数使得文件位置指针返回文件开头。

  (2)ftell 函数:

    原型为:long ftell(FILE *);

    执行成功时,返回当前文件指针到文件头有多少个字节,否则,返回-1。

    当文件指针到达文件末尾时,也可使用ftell获取文件大小。

       在windows上ftell获取文本文件的大小,换行符会解析成两个字符/r/n,linux上为一个字符,并且linux有结束符。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

void main()
{
    FILE *fp = fopen("c:\\1.txt", "r");

    if (fp == NULL)
    {
        printf("文件打开失败!\n");
    }
    else
    {
        while (!feof(fp))                    //没有到文件结尾就继续
        {
            char ch = getc(fp);              //从文件读取一个字符

            if (ch == 'o')
            {
                int len = ftell(fp);        //获取距离文件开头的字节数
                printf("\n\n找到o,距离文件开头%d字节\n\n",len);
            }

            putchar(ch);
        }

        int size = ftell(fp);                //到了文件末尾可以获取大小
        printf("\n文件大小有%d字节\n",size);

        //上面读取文件,文件指针已经到了末尾,下面再次读取需使用rewind
        rewind(fp);                          //文件指针回到开头

        char str[100] = { 0 };
        while (fgets(str, 100, fp) != NULL)
        {
            printf("%s", str);               //打印字符串
        }
    }

    fclose(fp);                              //关闭文件

    system("pause");
}

  (3)fseek 函数:

    文件定位中最重要的一个函数是fseek,用以控制、调整文件指针的值,从而改变下一次读写操作的位置,其函数原型为:int fseek(FILE * fp, long offset, int startPos);

    其中,fp是文件指针,startPos是起始点,offset是目标位置相对起始点的偏移量,可以为负数,如果函数操作执行成功,文件位置指针将被设定为“起始点+offset”,起始点并不是任意设定的,C语言给出了3种起始点方式,如下所示:

      

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

//fseek可以移动到指定位置进行读写
void main()
{
    FILE *fp = fopen("c:\\1.txt", "r+");

    if (fp == NULL)
        printf("文件打开失败!\n");
    else
    {
        printf("文件打开成功!\n");    //一开始文件指针再开头


        //移动到尾部进行写入,移动到尾部前面几个字节进行写入
        //输出结果为:先是在文件末尾输入“锄禾日当午”,然后刷新缓冲区往前移动10个字符覆盖输入“汗滴禾下土”。 
        //fseek(fp, 0, SEEK_END);        //移动文件指针到末尾
        //fputs("锄禾日当午", fp);         //输出字符串
        //fflush(fp);                    //将缓冲区数据立即写入文件
        //fseek(fp, -10, SEEK_END);      //往前移动10个字节(5个汉字占10字节)
        //fputs("汗滴禾下土", fp);         //输出字符串


        //读取文件后10个字节的内容
        //fseek(fp, -10, SEEK_END);       //移动指针到末尾前10个字节处
        //while (!feof(fp))
        //{
        //    char ch = fgetc(fp);        //获取一个字符
        //    putchar(ch);                //输出字符
        //}


        //修改前面8个字节
        //先显示一次:
        //while (!feof(fp))
        //{
        //    char ch = fgetc(fp);        //获取一个字符
        //    putchar(ch);                //输出字符
        //}
        //printf("\n-----------------------------------------------\n");    //分割行

        //fseek(fp, 0, SEEK_SET);        //移动到开头
        //for (int i = 0; i < 8; i++)    //写入8个字符'1'
        //    fputc('1', fp);

        ////再显示一次:
        //fseek(fp, 0, SEEK_SET);        //移动到开头
        //while (!feof(fp))
        //{
        //    char ch = fgetc(fp);        //获取一个字符
        //    putchar(ch);                //输出字符
        //}


        //文件中查找某个字符u,并修改前面4个字符
        while (!feof(fp))
        {
            char ch = fgetc(fp);          //获取一个字符
            putchar(ch);                  //输出字符
        }

        printf("\n-----------------------------------------------\n");    //分割行
        rewind(fp);                        //文件指针回到开头

        fseek(fp, 0, SEEK_SET);            //移动到开头
        while (!feof(fp))
        {
            char ch = fgetc(fp);        //获取一个字符
            if (ch == 'u')
            {
                fseek(fp, -4, SEEK_CUR);//当前位置向前移动4个字符
                fputc('1', fp);
                fputc('2', fp);
                fputc('3', fp);
                fputc('4', fp);
                break;                    //跳出循环
            }
        }
        //再次显示
        fseek(fp, 0, SEEK_SET);            //移动到开头
        while (!feof(fp))
        {
            char ch = fgetc(fp);          //获取一个字符
            putchar(ch);                  //输出字符
        }

        fclose(fp);
    }

    system("pause");
}

10. 删除文件,remove 函数:

  用 法: int remove(const char *filename);

  返回值:如果删除成功,remove返回0,否则返回EOF(-1)。

  如果要删除的文件已经打开,则删除失败返回 -1。

#include <stdio.h>
#include <stdlib.h>

void main()
{
    //char *Filepath = "c:\\2.txt";
    //remove(Filepath);                //删除文件,传入路径

    char *Filepath = "c:\\2.txt";
    int res = remove(Filepath);        //删除文件,传入路径
    printf("%d\n", res);

    if (res == 0)
        printf("删除成功!\n");
    else
        printf("删除失败!\n");

    system("pause");
}

11. 产生唯一的临时文件名,mktemp 函数:

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

返回值: 文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回NULL,并把错误代码存在errno中。

头文件是io.h。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <io.h>        //windows下mktemp()函数所在头文件;而linux下在头文件<stdlib.h>中

void main()
{
    char Filepath[100] = "c:\\XXXXXX";        //mktemp修改的目标,后面6个必须是X
    char *newName = _mktemp(Filepath);        //传入路径,根据模板生成唯一的目录名
    printf("%s,%s\n", newName, Filepath);

    char cmd[100];
    sprintf(cmd, "md %s", Filepath);        //初始化字符串,用于指令创建目录
    system(cmd);

    system("pause");
}