当前位置: 首页 > news >正文

c语言:文件操作

1. 为什么使⽤⽂件?

如果没有⽂件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失 了,等再次运⾏程序,是看不到上次程序的数据的,如果要将数据进⾏持久化的保存,我们可以使⽤ ⽂件。

2. 什么是⽂件?

磁盘(硬盘)上的⽂件是⽂件。

但是在程序设计中,我们⼀般谈的⽂件有两种:程序⽂件、数据⽂件(从⽂件功能的⻆度来分类 的)。

2.1 程序⽂件

程序⽂件包括源程序⽂件(后缀为.c),⽬标⽂件(windows环境后缀为.obj),可执⾏程序(windows 环境后缀为.exe)。

2.2 数据⽂件

⽂件的内容不⼀定是程序,⽽是程序运⾏时读写的数据,⽐如程序运⾏需要从中读取数据的⽂件,或 者输出内容的⽂件。

本篇文章讨论的是数据⽂件。

在以前各章所处理数据的输⼊输出都是以终端为对象的,即从终端的键盘输⼊数据,运⾏结果显⽰到 显⽰器上。

其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使⽤,这⾥处 理的就是磁盘上⽂件。

2.3 ⽂件名

⼀个⽂件要有⼀个唯⼀的⽂件标识,以便⽤⼾识别和引⽤。

⽂件名包含3部分:⽂件路径+⽂件名主⼲+⽂件后缀

例如: c:\code\test.txt

为了⽅便起⻅,⽂件标识常被称为⽂件名。

3. ⼆进制⽂件和⽂本⽂件?

根据数据的组织形式,数据⽂件被称为⽂本⽂件或者⼆进制⽂件。

数据在内存中以⼆进制的形式存储,如果不加转换的输出到外存的⽂件中,就是⼆进制⽂件。 如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的⽂件就是⽂ 本⽂件。

⼀个数据在⽂件中是怎么存储的呢? 字符⼀律以ASCII形式存储,数值型数据既可以⽤ASCII形式存储,也可以使⽤⼆进制形式存储。  如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占⽤5个字节(每个字符⼀个字节),⽽ ⼆进制形式输出,则在磁盘上只占4个字节。

4. ⽂件的打开和关闭

4.1 流和标准流

4.1.1 流

我们程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,不同的外部设备的输⼊输出 操作各不相同,为了⽅便程序员对各种设备进⾏⽅便的操作,我们抽象出了流的概念,我们可以把流 想象成流淌着字符的河。

C程序针对⽂件、画⾯、键盘等的数据输⼊输出操作都是通过流操作的。

⼀般情况下,我们要想向流⾥写数据,或者从流中读取数据,都是要打开流,然后操作。

4.1.2 标准流

那为什么我们从键盘输⼊数据,向屏幕上输出数据,并没有打开流呢?

那是因为C语⾔程序在启动的时候,默认打开了3个流:

• stdin - 标准输⼊流,在⼤多数的环境中从键盘输⼊,scanf函数就是从标准输⼊流中读取数据。

• stdout - 标准输出流,⼤多数的环境中输出⾄显⽰器界⾯,printf函数就是将信息输出到标准输出 流中。

• stderr - 标准错误流,⼤多数环境中输出到显⽰器界⾯。

这是默认打开了这三个流,我们使⽤scanf、printf等函数就可以直接进⾏输⼊输出操作的。

stdin、stdout、stderr 三个流的类型是: FILE* ,通常称为⽂件指针。  C语⾔中,就是通过 FILE* 的⽂件指针来维护流的各种操作的。

4.2 ⽂件指针

缓冲⽂件系统中,关键的概念是“⽂件类型指针”,简称“⽂件指针”。

每个被使⽤的⽂件都在内存中开辟了⼀个相应的⽂件信息区,⽤来存放⽂件的相关信息(如⽂件的名 字,⽂件状态及⽂件当前的位置等)。这些信息是保存在⼀个结构体变量中的。该结构体类型是由系 统声明的,取名FILE.

例如,VS2013 编译环境提供的 stdio.h 头⽂件中有以下的⽂件类型申明:

struct _iobuf {char *_ptr;int _cnt;char *_base;int _flag;int _file;int _charbuf;int _bufsiz;char *_tmpfname;};
typedef struct _iobuf FILE;

不同的C编译器的FILE类型包含的内容不完全相同,但是⼤同⼩异。

不同的C编译器的FILE类型包含的内容不完全相同,但是⼤同⼩异。

每当打开⼀个⽂件的时候,系统会根据⽂件的情况⾃动创建⼀个FILE结构的变量,并填充其中的信 息,使⽤者不必关⼼细节。 ⼀般都是通过⼀个FILE的指针来维护这个FILE结构的变量,这样使⽤起来更加⽅便。

下⾯我们可以创建⼀个FILE*的指针变量:

FILE* p;

定义pf是⼀个指向FILE类型数据的指针变量。可以使pf指向某个⽂件的⽂件信息区(是⼀个结构体变 量)。通过该⽂件信息区中的信息就能够访问该⽂件。也就是说,通过⽂件指针变量能够间接找到与 它关联的⽂件。

4.3 ⽂件的打开和关闭

⽂件在读写之前应该先打开⽂件,在使⽤结束之后应该关闭⽂件。 在编写程序的时候,在打开⽂件的同时,都会返回⼀个FILE*的指针变量指向该⽂件,也相当于建⽴了 指针和⽂件的关系。

ANSI C 规定使⽤ fopen 函数来打开⽂件, fclose 来关闭⽂件。

//打开⽂件 
FILE * fopen ( const char * filename, const char * mode );
//关闭⽂件 
int fclose ( FILE * stream );

mode表⽰⽂件的打开模式,下⾯都是⽂件的打开模式:

⽂件使⽤⽅式含义如果指定⽂件不存在
“r”(只读)为了输⼊数据,打开⼀个已经存在的⽂本⽂件出错
“w”(只写)为了输出数据,打开⼀个⽂本⽂件建⽴⼀个新的⽂件
“a”(追加)向⽂本⽂件尾添加数据建⽴⼀个新的⽂件
“rb”(只读)为了输⼊数据,打开⼀个⼆进制⽂件出错
“wb”(只写)为了输出数据,打开⼀个⼆进制⽂件建⽴⼀个新的⽂件
“r+”(读写)为了读和写,打开⼀个⽂本⽂件出错
“w+”(读写)为了读和写,建议⼀个新的⽂件建⽴⼀个新的⽂件
“a+”(读写)打开⼀个⽂件,在⽂件尾进⾏读写建⽴⼀个新的⽂件
“rb+”(读写)为了读和写打开⼀个⼆进制⽂件出错
“wb+”(读 写)为了读和写,新建⼀个新的⼆进制⽂件建⽴⼀个新的⽂件
“ab”(追加)向⼀个⼆进制⽂件尾添加数据建⽴⼀个新的⽂件
“ab+”(读 写)打开⼀个⼆进制⽂件,在⽂件尾进⾏读和写建⽴⼀个新的⽂件

实例代码:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{FILE* pf = fopen("text.txt", "w");if (pf == NULL){perror("fopen");return 1;}//写文件//关闭文件fclose(pf);pf = NULL;return 0;
}

5. ⽂件的顺序读写

5.1 顺序读写函数介绍

函数名功能适⽤于
fgetc字符输⼊函数所有输⼊流
fputc字符输出函数所有输出流
fgets⽂本⾏输⼊函数所有输⼊流
fputs⽂本⾏输出函数所有输出流
fscanf格式化输⼊函数所有输⼊流
fprintf格式化输出函数所有输出流
fread⼆进制输⼊

⽂件

fwrite⼆进制输出⽂件

上⾯说的适⽤于所有输⼊流⼀般指适⽤于标准输⼊流和其他输⼊流(如⽂件输⼊流);所有输出流⼀ 般指适⽤于标准输出流和其他输出流(如⽂件输出流)。

5.1.1 fgetc

fgetc函数从流中读字符。

int fgetc ( FILE * stream );

 例如:

#include <stdio.h>
int main ()
{FILE * pFile;int c;int n = 0;pFile=fopen ("myfile.txt","r");if (pFile==NULL) perror ("Error opening file");else{do {c = fgetc (pFile);if (c == '$') n++;} while (c != EOF);fclose (pFile);printf ("The file contains %d dollar sign characters ($).\n",n);}return 0;
}

该程序逐字符读取一个名为myfile.txt的现有文件,并使用n变量来计算文件中包含的美元字符数($)。

5.1.2 fputc

fputc函数写字符到流中

int fputc ( int character, FILE * stream );

 例如:

 此程序会创建一个名为example.txt的文件,并将abcdefghijklmnopqrstuvwxyz写入其中。

5.1.3 fgets

fgets从流中读字符串

char * fgets ( char * str, int num, FILE * stream );

 参数

str指向复制读取字符串的字符数组的指针。

num要复制到str中的最大字符数(包括终止的null字符)。

stream指向标识输入流的FILE对象的指针。std不能用作从标准输入读取的参数。

返回值

成功后,函数返回str。如果在尝试读取字符时遇到文件的末尾,则指示符号集(feof)的末尾。若在读取任何字符之前发生这种情况,则返回的指针为空指针(并且存储的内容不变)。如果发生读取错误,则会设置错误指示器(ferror),并返回一个空指针(但str指向的内容可能已更改)。

例如

#include <stdio.h>int main()
{FILE * pFile;char mystring [100];pFile = fopen ("myfile.txt" , "r");if (pFile == NULL) perror ("Error opening file");else {if ( fgets (mystring , 100 , pFile) != NULL )puts (mystring);fclose (pFile);}return 0;
}

 此示例读取myfile.tx的第一行或前99个字符(以先到者为准),并将它们打印在屏幕上。

5.1.4 fputs

fputs函数将字符串写入

int fputs(const char *str, FILE *stream);
  • str 是要写入的字符串。
  • stream 是要写入的文件流

fputs 函数会将字符串 str 中的字符逐个写入到文件流 stream 中,直到遇到字符串结束符 \0。如果成功写入,则返回非负值;如果发生错误,则返回 EOF

例如:

#include <stdio.h>
int main()
{FILE* pc = fopen("example.txt", "w");if (pc == NULL){perror("fopen");return 1;}else{fputs("ma jun jin da chang", pc);}return 0;
}

 

6. ⽂件的随机读写

6.1 fseek

fseek 是 C 语言中的一个标准库函数,用于设置文件流的位置指针,从而在文件中定位到特定的位置。它的函数原型如下:

int fseek ( FILE * stream, long int offset, int origin );
  • stream 是要设置位置的文件流,通常是通过 fopen 打开的文件指针。
  • offset 是偏移量,表示相对于 origin 的位置偏移。它的类型为 long int,通常是以字节为单位的偏移量。
  • origin 是起始位置,可以是下列常量之一:
    • SEEK_SET:从文件起始位置开始计算偏移量。
    • SEEK_CUR:从当前位置开始计算偏移量。
    • SEEK_END:从文件末尾位置开始计算偏移量。

fseek 函数会将文件流 stream 的位置指针设置为由 offset 和 origin 指定的位置。如果成功设置位置指针,则返回 0;如果发生错误,则返回非零值。

通过 fseek 函数,可以在文件中进行随机访问,定位到特定位置读取或写入数据。

例如:


#include <stdio.h>
int main ()
{FILE * pFile;pFile = fopen ( "example.txt" , "wb" );fputs ( "This is an apple." , pFile );fseek ( pFile , 9 , SEEK_SET );fputs ( " sam" , pFile );fclose ( pFile );return 0;
}

6.2 ftell

 ftell 是 C 语言中的一个标准库函数,用于获取文件流的当前位置指针相对于文件起始位置的偏移量(以字节为单位)。它的函数原型如下:

long int ftell(FILE *stream);
  • stream 是要获取位置指针的文件流,通常是通过 fopen 打开的文件指针。

ftell 函数返回当前位置指针相对于文件起始位置的偏移量。如果成功获取,则返回当前位置的偏移量;如果发生错误,则返回 -1L

通常情况下,ftell 结合 fseek 可以用来获取当前文件的大小,或者在文件操作中记录当前位置以便后续操作。

http://www.lryc.cn/news/325863.html

相关文章:

  • C#事件实例详解
  • 零基础机器学习(3)之机器学习的一般过程
  • 用java做一个双色球彩票系统
  • 某对象存储元数据集群改造流水账
  • 前端理论总结(js)——filter、foearch、for in 、for of 、for的区别以及返回值
  • 【JavaEE初阶系列】——多线程案例一——单例模式 (“饿汉模式“和“懒汉模式“以及解决线程安全问题)
  • 革新水库大坝监测:传统软件与云平台之比较
  • C++模版(基础)
  • MySQL驱动Add Batch优化实现
  • 手撕算法-数组中的第K个最大元素
  • 【vue】computed和watch的区别和应用场景
  • ARM.day8
  • SpringCloud Gateway工作流程
  • 西井科技与安通控股签署战略合作协议 共创大物流全新生态
  • CCCorelib 点云RANSAC拟合球体(CloudCompare内置算法库)
  • map china not exists. the geojson of the map must be provided.
  • Redis如何删除大key
  • JRT菜单
  • 《海王2》观后感
  • [蓝桥杯 2023 省 A] 颜色平衡树:从零开始理解树上莫队 一颗颜色平衡树引发的惨案
  • maya打开bvh脚本
  • 【JavaSE】数据类型和运算符
  • Docker 哲学 - ip 的组成规则 与 网关介绍
  • 数学建模竞赛真的是模型解题一般,但是论文出彩而获奖的吗?
  • 深度学习常见的三种模型
  • 接口自动化测试分层设计与实践总结
  • 集合(下)Map集合的使用
  • AAPT: error: resource android:attr/dialogCornerRadius not found.
  • 数字功放VS模拟功放,选择适合你的音频解决方案
  • 5.88 BCC工具之tcpsynbl.py解读