c语言基础笔记DAY8_文件操作

本文详细介绍了C语言中的文件操作,包括文件指针的概念、文件的打开与关闭、字符读写函数fputc与fgetc、文件结尾检测feof、字符串读写函数fputs与fgets等。此外还讲解了文件缓冲区的概念及其作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

c语言基础笔记DAY8_文件操作

1.认识文件指针

在C语言中用一个指针变量指向一个文件,这个指针称为文件指针。

typedef struct
{short      level; //缓冲区"满"或者"空"的程度 unsigned    flags;   //文件状态标志 char      fd;      //文件描述符unsigned char  hold;    //如无缓冲区不读取字符short      bsize; //缓冲区的大小unsigned char  *buffer;//数据缓冲区的位置 unsigned    ar;   //指针,当前的指向 unsigned    istemp;  //临时文件,指示器short      token;    //用于有效性的检查 
}FILE;

FILE是系统使用typedef定义出来的有关文件信息的一种结构体类型,结构中含有文件名、文件状态和文件当前位置等信息。

声明FILE结构体类型的信息包含在头文件“stdio.h”中,一般设置一个指向FILE类型变量的指针变量,然后通过它来引用这些FILE类型变量。通过文件指针就可对它所指的文件进行各种操作。

C语言中有三个特殊的文件指针由系统默认打开,用户无需定义即可直接使用
stdin标准输入,默认为当前终端(键盘),我们使用的scanf、getchar函数默认从此终端获得数据
stdout标准输出,默认为当前终端(屏幕),我们使用的printf、puts函数默认输出信息到此终端
stderr标准出错,默认为当前终端(屏幕),我们使用的perror函数默认输出信息到此终端

类似 : FILE*stdout = fopen(“stdout”,“w”);

2.文件的打开

任何文件使用之前必须打开:

#include <stdio.h>
FILE * fopen(const  char * filename, const char * mode);

功能: 打开文件

参数:

​ filename:需要打开的文件名,根据需要加上路径

​ mode:打开文件的模式设置

返回值:

​ 成功:文件指针

​ 失败:NULL

第一个参数的几种形式:

	FILE*fp_passwd = NULL;//相对路径://打开当前目录passdw文件:源文件(源程序)所在目录
​    FILE*fp_passwd = fopen("passwd.txt", "r");
​    
​    //打开当前目录(test)下passwd.txt文件
​    fp_passwd = fopen(". / test / passwd.txt", "r");
​    
​    //打开当前目录上一级目录(相对当前目录)passwd.txt文件
​    fp_passwd = fopen(".. / passwd.txt", "r");
​       
​    //绝对路径://打开C盘test目录下一个叫passwd.txt文件
​    fp_passwd = fopen("c:/test/passwd.txt","r");

第二个参数的几种形式(打开文件的方式):

打开模式含义
r或rb以只读方式打开一个文本文件(不创建文件,若文件不存在则报错)
w或wb以写方式打开文件(如果文件存在则==清空==文件,文件不存在则创建一个文件)
a或ab以追加方式打开文件,在末尾添加内容,若文件不存在则创建文件
r+或rb+以可读、可写的方式打开文件(不创建新文件)
w+或wb+以可读、可写的方式打开文件(如果文件存在则==清空==文件,文件不存在则创建一个文件)
a+或ab+以添加方式打开文件,打开文件并在末尾更改文件,若文件不存在则创建文件

注意:

  • b是二进制模式的意思,b只是在Windows有效,在Linux用r和rb的结果是一样的

  • Unix和Linux下所有的文本文件行都是\n结尾,而Windows所有的文本文件行都是\r\n结尾

  • 在Windows平台下,以“文本”方式打开文件,不加b:

    • 当读取文件的时候,系统会将所有的 “\r\n” 转换成 “\n”
    • 当写入文件的时候,系统会将 “\n” 转换成 “\r\n” 写入
    • 以"二进制"方式打开文件,则读写都不会进行这样的转换
  • 在Unix/Linux平台下,“文本”与“二进制”模式没有区别,"\r\n" 作为两个字符原样输入输出

int main(void)

{
​    FILE *fp = NULL;// "\\"这样的路径形式,只能在windows使用// "/"这样的路径形式,windows和linux平台下都可用,建议使用这种// 路径可以是相对路径,也可是绝对路径
​    fp = fopen("../test", "w");//fp = fopen("..\\test", "w");if (fp == NULL) //返回空,说明打开失败{//perror()是标准出错打印函数,能打印调用库函数出错原因perror("open");return -1;}return 0;
}
3.关闭文件

fclose(FILE*fp)

  • 功能 : 关闭文件流
4.fputc()

语法:

  #include <stdio.h>
  int fputc( int ch, FILE *stream ); 

函数fputc()把给出的字符ch写到给出的输出流. 返回值是字符, 发生错误时返回值是EOF.

5.fgetc

语法:

  #include <stdio.h>
  int fgetc( FILE *stream ); 
  • fgetc()函数返回来自stream(流)中的下一个字符,如果到达文件尾或者发生错误时返回EOF.
  • EOF == -1
int main()
{
	FILE*fp = fopen("./a.txt", "r");
	char buf[128] = { 0 };
	int i = 0;
	while ((buf[i++] = fgetc(fp)) != -1);
	system("pause");
	return 0;
}
6.feof()文件结尾
#include <stdio.h>

int feof(FILE* stream);

功能:

​ 检测是否读取到了文件结尾。判断的是最后一次“读操作的内容”,不是当前位置内容(上一个内容)。

参数:

​ stream:文件指针

返回值:

​ 非0值:已经到文件结尾

​ 0:没有到文件结尾

7.fputs

注意 : fputs写入时,遇到’\n’,会继续写入

#include <stdio.h>

int fputs(const  char * str,FILE* stream);

功能:

​ 将str所指定的字符串写入到stream指定的文件中,字符串结束符 ‘\0’ 不写入文件。

参数:

​ str:字符串

​ stream:文件指针

返回值:

​ 成功:0

​ 失败:-1

8.fgets

注意 : fgets读取时,遇到’\n’,会停止读取.’\n’会被读取到buf中

#include <stdio.h>

char* fgets(char* buf, int  size,  FILE*stream);

功能:

​ 从stream指定的文件内读入字符,保存到str所指定的内存空间,直到出现换行字符、读到文件结尾或是已读了size - 1个字符为止,最后会自动加上字符 ‘\0’ 作为字符串结束。

参数:

​ buf:字符串

​ size:指定最大读取字符串的长度(size - 1)

​ stream:文件指针

返回值:

​ 成功:成功读取的字符串

​ 读到文件尾或出错: NULL

9.fprintf

语法:

  #include <stdio.h>
  int fprintf( FILE *stream, const char *format, ... ); 

fprintf()函数根据指定的format(格式)(格式)发送信息(参数)到由stream(流)指定的文件.

fprintf()只能和printf()一样工作. fprintf()的返回值是输出的字符数,发生错误时返回-1.

示例:

    char name[20] = "Mary";
    FILE *out;
    out = fopen( "output.txt", "w" );
    if( out != NULL )
    fprintf( out, "Hello %s\n", name );
10.fscanf

语法:

  #include <stdio.h>  
  int fscanf( FILE *stream, const char *format, ... ); 

函数fscanf()以scanf()的执行方式从给出的文件流中读取数据.

fscanf()的返回值是事实上已赋值的变量的数,如果未进行任何分配时返回EOF.

11.fwrite
#include <stdio.h>
size_t fwrite(const void*ptr,size_t size,size_t nmemb,FILE*stream);

功能:以数据块的方式给文件写入内容

参数:

​ ptr:准备写入文件数据的地址

​ size: size_t 为 unsigned int类型,此参数指定写入文件内容的块数据大小

​ nmemb:写入文件的块数,写入文件数据总大小为:size * nmemb

​ stream:已经打开的文件指针

返回值:

​ 成功:实际成功写入文件数据的块数目,此值和 nmemb 相等

12.fread
#include <stdio.h>

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

功能:以数据块的方式从文件中读取内容

参数:

​ ptr:存放读取出来数据的内存空间

​ size: size_t 为 unsigned int类型,此参数指定读取文件内容的块数据大小

​ nmemb:读取文件的块数,读取文件数据总大小为:size * nmemb

​ stream:已经打开的文件指针

返回值:

​ 成功:实际成功读取到内容的块数,如果此值比nmemb小,但大于0,说明读到文件的结尾。

​ 失败:0



文件光标操作(随机读写)

13.fseek
#include <stdio.h>
int fseek(FILE*stream, long offset,int whence);

功能:

​ 移动文件流(文件光标)的读写位置。

参数:

stream:已经打开的文件指针

offset:根据whence来移动的位移数(偏移量),可以是正数,也可以负数,如果正数,则相对于whence往右移动,如果是负数,则相对于whence往左移动。如果向前移动的字节数超过了文件开头则出错返回,如果向后移动的字节数超过了文件末尾,再次写入时将增大文件尺寸。

whence:其取值如下:

​ SEEK_SET:从文件开头移动offset个字节

​ SEEK_CUR:从当前位置移动offset个字节

​ SEEK_END:从文件末尾移动offset个字节

返回值:

​ 成功:0

​ 失败:-1

14.ftell
#include <stdio.h>
long ftell(FILE*stream);

功能:获取文件流(文件光标)的读写位置。

参数:

​ stream:已经打开的文件指针

返回值:

​ 成功:当前文件流(文件光标)的读写位置

​ 失败:-1

15.rewind
#include <stdio.h>
void rewind( FILE*stream);

功能:把文件流(文件光标)的读写位置移动到文件开头。

参数:

​ stream:已经打开的文件指针

返回值:

​ 无返回值

typedef struct Stu

{char name[50];
 int id;
}Stu;
//假如已经往文件写入3个结构体
//fwrite(s, sizeof(Stu), 3, fp);
Stu s[3];

Stu tmp; 

int ret = 0;

//文件光标读写位置从开头往右移动2个结构体的位置

fseek(fp, 2 * sizeof(Stu), SEEK_SET);

//读第3个结构体

ret = fread(&tmp, sizeof(Stu), 1, fp);

if (ret == 1)
{printf("[tmp]%s, %d\n", tmp.name, tmp.id);
}

//把文件光标移动到文件开头
//fseek(fp, 0, SEEK_SET);

rewind(fp);

ret = fread(s, sizeof(Stu), 3, fp);

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

int i = 0;

for (i = 0; i < 3; i++)
{printf("s === %s, %d\n", s[i].name, s[i].id);
}




16. 获取文件状态
#include <sys/types.h>
#include <sys/stat.h>
int stat(const char * path, struct stat * buf );

功能:获取文件状态信息

参数:

​ path:文件名

​ buf:保存文件信息的结构体

返回值:

​ 成功:0

​ 失败-1

结构体成员

struct stat 
{
    dev_t     st_dev;     //文件的设备编号
    ino_t     st_ino;      //节点
    mode_t    st_mode;  //文件的类型和存取的权限
    nlink_t    st_nlink;   //连到该文件的硬连接数目,刚建立的文件值为1
    uid_t     st_uid;     //用户ID
    gid_t     st_gid;     //组ID
    dev_t     st_rdev;   //(设备类型)若此文件为设备文件,则为其设备编号
    off_t     st_size;    //文件字节数(文件大小)
    unsigned long st_blksize;  //块大小(文件系统的I/O 缓冲区大小)
    unsigned long st_blocks;  //块数
    time_t    st_atime;   //最后一次访问时间
    time_t    st_mtime;  //最后一次修改时间
    time_t    st_ctime;   //最后一次改变时间(指属性)
};

#include <sys/types.h>

#include <sys/stat.h>

#include <stdio.h>

int main(int argc, char **args)

{

​ if (argc < 2)

​ return 0;

​ struct stat st = { 0 };

stat(args[1], &st);

​ int size = st.st_size; //得到结构体中的成员变量

printf("%d\n", size);

​ return 0;

}

17. 删除文件、重命名文件名
#include <stdio.h>
int remove(const char*pathname);

功能:删除文件

参数:

​ pathname:文件名

返回值:

​ 成功:0

​ 失败:-1

#include <stdio.h>
int  rename(const char*oldpath,const char*newpath);

功能:把oldpath的文件名改为newpath

参数:

oldpath:旧文件名

newpath:新文件名

返回值:

成功:0

失败: - 1

18.缓冲区
  1. 什么叫缓冲区?

    缓冲区又称为缓存,它是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做 缓冲区 。

    缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区。

  2. 为什么要引入缓冲区?

    缓冲区就是一块内存区,它用在输入输出设备和CPU之间,用来缓存数据。它使得低速的输入输出设备和高速的CPU能够协调工作,避免低速的输入输出设备占用CPU,解放出CPU,使其能够高效率工作。

    类似快递员送快递.若是来一个快递,送一次,必然工作效率大大降低.若是当快递堆积到一定量时再送,则效率显著提高

  3. 缓冲区分类

    缓冲区 分为三种类型:全缓冲、行缓冲和不带缓冲。

    1. 全缓冲
      在这种情况下,当填满标准I/O缓存后才进行实际I/O操作。全缓冲的典型代表是对磁盘文件的读写。

    2. 行缓冲
      在这种情况下,当在输入和输出中遇到换行符时,执行真正的I/O操作。这时,我们输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的I/O操作。典型代表是标准输入(stdin)和标准输出(stdout)。

    3. 不带缓冲
      也就是不进行缓冲,标准出错情况stderr是典型代表,这使得出错信息可以直接尽快地显示出来。

  4. 缓冲区大小

    如果我们没有自己设置缓冲区的话,系统会默认为标准输入输出设置一个缓冲区,这个缓冲区的大小通常是512个字节的大小。

    缓冲区大小由 stdio.h 头文件中的宏 BUFSIZ 定义,如果希望查看它的大小,包含头文件,直接输出它的值即可:

    printf(“%d”, BUFSIZ);
    

    缓冲区的大小是可以改变的,也可以将文件关联到自定义的缓冲区,详情可以查看 setvbuf()setbuf() 函数。

  5. 清空缓冲区

    下列情况会引发缓冲区的刷新:

    • 缓冲区满时;

    • 行缓冲区遇到回车时;

    • 关闭文件;

    • 使用特定函数刷新缓冲区。

      • 刷新缓冲区函数

        #include <stdio.h>

        int fflush(FILE * stream);

        功能:更新缓冲区,让缓冲区的数据立马写到文件中。

        参数:

        stream:文件指针

        返回值:

        成功:0

        失败:-1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值