- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章C语言文件操作的入门详解教程由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
文件有千千万万,但是在我们的程序设计当中,我们谈的文件一般有两种:
1.程序文件 。
包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe).
2.数据文件 。
文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件.
而在本节中,我们主要提到的是数据文件.
我们知道,名字都是用来标识和区别事物的,那么文件名也是这样,是区别各个文件的标识.
一个文件名要包含 3 个部分:文件路径+文件名主干+文件后缀 。
如:C:\Windows\System32\drivers\etc.txt 。
其中 :C:\Windows\System32\drivers\ 是文件路径,etc 是文件名主干,txt 是文件名后缀.
当然了,各个平台的文件路径并不相同,以及为了方便起见文件标识通常别称为文件名 。
根据数据的组织形式,数据文件被称为文本文件或者二进制文件.
二进制文件:数据在内存中以二进制的形式存储,并不加转换的输出到外存.
文本文件:要求在外存上以ASCII码的形式存储,需要在存储前转换,以ASCII字符的形式存储的文件.
那么一个数据在内存中是怎样存储的呢?
字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储.
如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节) 。
而二进制形式输出,则在磁盘上只占4个字节(VS2019测试).
如:
我们可以测试一番:
#include <stdio.h>int main(){ int a = 10000; FILE* pf = fopen("test.txt", "wb"); fwrite(&a, 4, 1, pf);//二进制的形式写到文件中 fclose(pf); pf = NULL; return 0;}
我们打开的时候要注意以二进制编辑器来打开,你会发现出现了如下图显示的一串数字,其中它们是以十六进制现实的,转换一下,刚好是上图显示的那串二进制数字(注意VS采用的是小端储存模式) 。
数据流:
指程序于数据的交互是以流的形式进行的,包括输入流与输出流; 。
输入流:
程序从输入流读取数据源。数据源包括键盘,文件,网络等,即:将数据源读入到程序的外界通道.
输出流:
程序向输出流写入数据。将程序中的数据输出到外界(显示器,打印机,文件,网络,等)的通信通道.
采用数据流的目的:使得输入输出独立于设备,不关心数据源来自何方,也不管输出的目的地是何种设备.
缓冲区:
指在程序运行时,所提供的额外内存,可用来暂时存放做准备执行的数据。它可在创建、访问、删除静态数据上,大大提高运行速度(速度的提高程度有时甚至可高达几十倍), 。
为我们提供了极大的便捷,节省了大量的时间与精力 。
文件缓冲区: 。
ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”.
从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区), 。
然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的.
如:
无论是输入输出,都先在缓冲区里存着,然后在进行输入输出.
缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”.
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等).
这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE.
我们可以来看在VS 2019中FILE的声明:
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+//// Stream I/O Declarations Required by this Header////-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+#ifndef _FILE_DEFINED#define _FILE_DEFINEDtypedef struct _iobuf{ void* _Placeholder;} FILE;#endif
不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异.
每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关心细节.
一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便.
如下:我们便创建了一个文件指针 。
FILE* pf;//文件指针变量
定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量).
通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件.
比如:
到此,我们的基本概念就结束了,下面进入到函数部分:
文件在使用前,我们肯定要打开文件;在使用结束后,我们需要关闭文件.
1.fopen() --- 文件打开函数 。
声明:文档 。
FILE* fopen(const char* filename, const char* mode),
参数:
const char* filename ---- 文件名 。
const char* mode ---- 文件打开方式 。
文件打开方式:
那,接下来看一个实例:
/* fopen example */#include <stdio.h>int main(){ FILE* pFile; pFile = fopen("myfile.txt", "w");//打开一个文件(没有就创建),以写的方式打开 if (pFile != NULL)//如果打开成功 { fputs("fopen example", pFile);//就往文件里写入 fopen example fclose(pFile);//关闭文件 } return 0;}
2.fclose() --- 文件关闭函数 。
声明:文档 。
int fclose(FILE* stream),
参数为要关闭文件的文件指针 。
示例:
int main(){ //相对路径 //.. 表示上一级目录 //. 当前目录 //FILE* pf = fopen("../data.txt", "r");//在上一级文件中打开data.txt,如果没有就报错 //绝对路径 C:\Windows\System32\drivers\etc.txt //./hehe/test.txt //../../ FILE* pf = fopen("../../data.txt", "r"); if (pf == NULL) { printf("打开文件失败\n"); printf("%s\n", strerror(errno));//注意头文件的包含 stding.h errno.h return 1;//失败返回 } //打开文件成功 printf("打开文件成功\n"); //读写文件 //... //关闭文件 fclose(pf); pf = NULL;//及时置NULL return 0;}
注:
其他的文件打开模式,将在函数讲解的时候一并讲解:
1. 字符输入输出函数 。
fput--- 向指定输出流输出一个字符声明 。
int fputc ( int character, FILE * stream ),
参数:
int character --- 所输入的字符 。
FILE * stream --- 指定输出流 。
fgetc--- 向指定输入流输入一个字符声明 。
int fgetc ( FILE * stream ),
参数:
FILE * stream --- 指定输入流 。
示例 1:
//在文件里写入a-z26个字母int main(){ //fopen函数如果是以写的形式打开 //如果文件不错在,会创建这个文件 //如果文件存在,会清空文件的内容 //fopen函数如果是以读的形式打开 //文件不存在打开失败 FILE* pf = fopen("data.txt", "w"); if (pf == NULL) { printf("%s\n", strerror(errno)); return 1;//失败返回 } //写文件 int i = 0; for (i = 'a'; i <= 'z'; i++) { fputc(i, pf);//在文件里写 --- pf 我们自己定义的文件指针 fputc(i, stdout);//显示在屏幕上 --- stdout --- 标准输出流 } // 从键盘输入 --- stdin --- 标准输入流 //关闭文件 fclose(pf); pf = NULL; return 0;}
这里需要注意的就是所指定的输出流:
在C语言所写的程序运行起来时,会默认打开三个流:
1.stdin - 标准输入流 (键盘) 。
2.stdout - 标准输出流 (屏幕) 。
3.stderr - 标准错误流(屏幕) 。
示例 2:
//从刚才写的文件,再把内容读出来int main(){ FILE* pf = fopen("data.txt", "r");// r 是以读的形式打开文件,如果没有该文件就报错 if (pf == NULL) { printf("%s\n", strerror(errno)); return 1; } //打开文件成功,读文件 //int ch = fgetc(pf); //printf("%c\n", ch);//a //ch = fgetc(pf); //printf("%c\n", ch);//b //ch = fgetc(pf); //printf("%c\n", ch);//c //ch = fgetc(pf); //printf("%c\n", ch);//d int ch = 0; while ((ch = fgetc(pf)) != EOF)// pf --- 所指定的输入流 { printf("%c ", ch); } //关闭文件 fclose(pf); pf = NULL; return 0;}
这里需要注意一点:
fgetc() 的返回值:我们在这就只说出现错误的信息:
If the position indicator was at theend-of-file, the function returnsEOFand sets theeof indicator(feof) ofstream. If some other reading error happens, the function also returnsEOF, but sets itserror indicator(ferror) instead. 。
翻译过来就是:
如果文件指针处于文件末端,则函数返回EOF,并设置流的eof指示器(feof) 如果发生其他读数错误,函数也会返回EOF,但会设置错误指示器(ferror) 。
这里的feof和ferror我们专门会放到最后讲 。
2.文本行输入输出函数 。
fputs--- 文本行输出行数声明 。
int fputs ( const char * str, FILE * stream ),
参数:
const char * str --- 将被写入输出流的字符指针 。
FILE * stream --- 输出流 。
fgets--- 文本行输入函数声明 。
char * fgets ( char * str, int num, FILE * stream ),
参数:
char * str --- 所输入信息的存放位置 。
int num --- 要读内容的大小 。
FILE * stream --- 输入流 。
示例 1:
int main(){ FILE* pf = fopen("data.txt", "a");// a --- 如果没有就该文件就创建,有就在该文件后方继续追加内容 if (pf == NULL) // 而 w 如果存在该文件会覆盖重写 { printf("%s\n", strerror(errno)); return 1; } //写一行数据 fputs("hello\n", pf);//输出到文件中 fputs("hello\n", stdout);//在屏幕上显示 fputs("hello world\n", pf);//输出到文件中 fputs("hello world\n",stdout);//在屏幕上显示 fclose(pf); pf = NULL; return 0;}
示例 2:
int main(){ char arr[100] = {0};//存放写入的信息 FILE* pf = fopen("data.txt", "r"); if (pf == NULL) { printf("%s\n", strerror(errno)); return 1; } //读一行数据 //fgets(arr, 100, pf); //printf("%s\n", arr); while (fgets(arr, 10, pf) != NULL)//输出---一次读十个 { printf("%s", arr); } //fgets从标准输入流中读取 fgets(arr, 100, stdin); printf("%s\n", arr); fclose(pf); pf = NULL; return 0;}
注意:
1.在fgets中num的大小数包含 \0 ,在内的,如果所输入的内容大小大于指定的大小,fgets会强行截断加 \0. 。
2.返回值的处理:
If theend-of-fileis encountered while attempting to read a character, theeof indicatoris set (feof). If this happens before any characters could be read, the pointer returned is a null pointer 。
(andthe contentsofstrremain unchanged). 。
If a read error occurs, theerror indicator(ferror) is set and a null pointer is also returned (but the contents pointed bystrmay have changed). 。
简单点说:遇到错误和文件结尾都会返回NULL,但会设置不同的指示器(feof,ferror)(后面会说) 。
3.格式化输入输出函数 。
fprintf--- 格式化输出函数 声明 。
int fprintf ( FILE * stream, const char * format, ... ),
fscanf--- 格式化输入函数声明 。
int fscanf ( FILE * stream, const char * format, ... ),
别看他们俩长得花里胡哨的,但是使用却和我们的printf,scanf大致相同,只是多出了一个流的填写 。
我们来看看 printf 和 scanf的声明:
int scanf ( const char * format, ... );int printf ( const char * format, ... ),
所以我们来看一个示例:
示例 1:
struct Stu{ char name[20]; int age; float score;};int main(){ struct Stu s = {"zhangsan", 20, 66.5f}; FILE* pf = fopen("data.txt", "w"); if (pf == NULL) { printf("%s\n", strerror(errno)); return 1; } //格式化的写入 fprintf(pf,"%s %d %f", s.name, s.age, s.score); //printf("%s %d %f", s.name, s.age, s.score);//对比一下只是差了一个 流 的指定 //关闭文件 fclose(pf); pf = NULL; return 0;}
注意:
读取错误或结束时,fscanf 的返回值也是EOF,判断同 fgetc 。
这里其实还有一组与它俩相似的函数 ---sprintf以及sscanf (点击函数名看文档) 。
它俩是干什么的呢,一个是把结构化的数据转换为字符串,一个是把字符串转化为结构化的数据 。
同样,我们来看看声明:
[code]int sprintf ( char * str, const char * format, ... ),
char * str --- 我们要把格式化生成的字符串所存放的地址 。
int sscanf ( const char * s, const char * format, ...),
const char * s --- 我们所要读取的字符串 。
示例:
struct Stu{ char name[20]; int age; float score;};int main(){ struct Stu s = {"zhangsan", 20, 66.5f}; char buf[200] = { 0 }; //sprintf可以把结构化的数据转换为一个字符串 sprintf(buf, "%s %d %f", s.name, s.age, s.score); printf("按照字符串的形式:%s\n", buf); struct Stu tmp = { 0 }; //sscanf可以把一个字符串转换为一个结构化的数据 sscanf(buf, "%s %d %f", tmp.name, &(tmp.age), &(tmp.score)); printf("按照格式化的形式:%s %d %f\n", tmp.name, tmp.age, tmp.score); return 0;}
4.二进制输入输出函数 。
fwrite--- 二进制写文档 。
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream ),
这个函数解释一下就是:将来自 ptr 指向的数据,一次写size个字节,共写 count 次,输出到 stream 指定的流中 。
fread--- 二进制读文档 。
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream ),
这个函数解释一下就是:将 stream 指定的流中 读 count 次,一次读 size 个字节,存到 ptr 所指向的内容中 。
示例:
// data.txt 内容 zhangsan 20 66.500000int main(){ struct Stu s = {0}; FILE* pf = fopen("data.txt", "rb");//binary --- 二进制 if (pf == NULL) // rb --- 二进制读 { printf("%s\n", strerror(errno)); return 1; } //读文件-二进制 fread(&s, sizeof(struct Stu), 1, pf); printf("%s %d %f\n", s.name, s.age, s.score); fclose(pf); pf = NULL; return 0;}
注:
若读取时发现读取的内容的个数比指定的最大个数小时,就结束,然后判断是读到文件末尾,还是读取失败 。
示例 2:
int main(){ int a = 10000; FILE*pf = fopen("bin.dat", "wb");//二进制写 if (pf == NULL) { return 1; } fwrite(&a, sizeof(int), 1, pf); fclose(pf); pf = NULL; return 0;}
1.seek ---根据文件指针的位置和偏移量来定位文件指针.
int fseek ( FILE * stream, long int offset, int origin ),
FILE * stream --- 流 。
long int offset --- 偏移量 。
int origin --- 从哪里开始,有三个选择 。
1.SEEK_SET --- 从文件头开始 。
2.SEEK_CUR --- 从当前位置开始 。
3.SEEk_END --- 从文件末尾开始 。
示例:
//此时文件内容为:123456789int main(){ FILE* fp = fopen("data.txt", "r"); if (fp == NULL) { perror("\n"); exit(1); } char a = fgetc(fp); printf("%c ", a);//此时结果为 1,现在指针指向 2 a = fgetc(fp);//此时读取2,指针指向 3 printf("%c ", a); fseek(fp, -1, SEEK_END);//将文件指针置于文章末尾 a = fgetc(fp);//此时读取9,指针再次指向末尾 printf("%c ", a); fseek(fp, 1, SEEK_SET);//将文件指针置于文章头 a = fgetc(fp);//此时读取1,指针再次指向2 printf("%c ", a); fclose(fp); fp = NULL; return 0;}
2.ftell ---返回文件指针相对于起始位置的偏移量 。
long int ftell ( FILE * stream ),
3.rewind ---让文件指针的位置回到文件的起始位置 。
void rewind ( FILE * stream ),
示例:
int main(){ FILE*pf = fopen("data.txt", "r"); if (pf == NULL) { return 1; } //读取 int ch = fgetc(pf); printf("%c\n", ch); ch = fgetc(pf); printf("%c\n", ch); //定位文件指针到文件的起始位置 //fseek(pf, -2,SEEK_CUR); //fseek(pf, 0, SEEK_SET); //printf("%d\n", ftell(pf)); rewind(pf); ch = fgetc(pf);//要在这里读取'a' printf("%c\n", ch); fclose(pf); pf = NULL; return 0;}
我们曾在上文提到文件缓冲区的概念:
缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”.
从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上.
如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等).
缓冲区的大小根据C编译系统决定的.
所以,当我们在程序中命令计算机往文件中写一些东西的时候,如果我们想在输出语句已结束,文件就有内容(即需要写的内容从文件缓冲区写到了文件中), 。
此时,我们不妨fflush一下 。
fflush --- 刷新文件缓存区 。
int fflush ( FILE * stream ),
参数就是我们所定义的文件指针.
示例:
#include <stdio.h>#include <windows.h>//VS2019 WIN10环境测试int main(){ FILE* pf = fopen("test.txt", "w"); fputs("abcdef", pf);//先将代码放在输出缓冲区 printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n"); Sleep(10000); printf("刷新缓冲区\n"); fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘) //注:fflush 在一些编译器上并不能使用 printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n"); Sleep(10000); fclose(pf); //注:fclose在关闭文件的时候,也会刷新缓冲区 pf = NULL; return 0;}
在刚才的讲解中,我们已经都说过了各输入函数遇到错误时的返回值,所以我们在写文件循环读取的循环条件时,一定要注意各函数的返回值的区别 ! 。
在不满足循环条件后 判断是发生错误跳出,还是读到文本末尾结束(这就是前面所说到的指示器 feof --- 文本结束, ferror --- 遇到错误) 。
如图:
示例:
int main(){ FILE*pf = fopen("data.txt", "r"); if (pf == NULL) { return 1; } //读取 int ch = 0; while ((ch = fgetc(pf)) != EOF) { printf("%c ", ch); } //找结束的原因 if (ferror(pf)) { printf("读取是发生错误,失败,而结束\n"); } else if (feof(pf)) { printf("遇到文件末尾,而结束的\n"); } fclose(pf); pf = NULL; return 0;}
所以,我们在日常使用的时候要注意这个点! 。
到此这篇关于C语言文件操作入门详解教程的文章就介绍到这了,更多相关C语言文件操作内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://www.cnblogs.com/guguguhuha/p/14594374.html 。
最后此篇关于C语言文件操作的入门详解教程的文章就讲到这里了,如果你想了解更多关于C语言文件操作的入门详解教程的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
Hive —— 入门 Hive介绍 Apache Hive是一款建立在Hadoop之上的开源数据仓库系统,可以将存储在Hadoop文件中的结构化、半结构化数据文件映射为一张数据库表,基于表提供了一
HBase —— 入门 HBase介绍 HBase是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的Google论文“Bigtable:一个结构化数据的分布式存储系统”
零:前端目前形势 前端的发展史 HTML(5)、CSS(3)、JavaScript(ES5、ES6):编写一个个的页面 -> 给后端(PHP、Python、Go、Java) ->
在本教程中,您将了解在计算机上运行 JavaScript 的不同方法。 JavaScript 是一种流行的编程语言,具有广泛的应用程序。 JavaScript 以前主要用于使网页具有交
我曾经是一个对编程一窍不通的小白,但因为对互联网世界的好奇心和求知欲的驱使,我踏入了编程的殿堂。在学习的过程中,我发现了一门神奇的编程语言——Python。Python有着简洁、易读的语法,让初学者能
嗨,亲爱的读者们! 今天我要给大家分享一些关于Python爬虫的小案例。你是否曾为了获取特定网页上的数据而烦恼过?或者是否好奇如何从网页中提取信息以供自己使用?那么,这篇文章将会给你一些启示和灵感。
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 8 年前。 Improv
我想创建一个像https://apprtc.appspot.com/?r=04188292这样的应用程序。我对 webrtc 了解一点,但无法掌握 google app-engine。如何为 java
我刚刚开始使用 Python 并编写了一个简单的周边程序。但是,每当我在终端中键入 python perimeter.py 时,都会收到以下错误,我不知道如何解决。 >>> python perime
Redis有5个基本数据结构,string、list、hash、set和zset。它们是日常开发中使用频率非常高应用最为广泛的数据结构,把这5个数据结构都吃透了,你就掌握了Redis应用知识的一半了
创建发布web项目 具体步骤: 1.在开发工具中创建一个dynamic web project helloword 2.在webContent中创建index.html文件 3.发布web应用到
如果你在 Ubuntu 上使用终端的时间很长,你可能会希望调整终端的字体和大小以获取一种良好的体验。 更改字体是一种最简单但最直观的 Linux 的终端自定义 的方法。让我
1. 前言 ADODB 是 Active Data Objects Data Base 的简称,它是一种 PHP 存取数据库的函式组件。现在 SFS3 系统 (校园自由软件交流网学务系统) 计划的
我对 neo4j 完全陌生,我很抱歉提出这样一个基本问题。我已经安装了neo4j,我正在使用shell“localhost:7474/webadmin/#/console/” 我正在寻找一个很好的例子
我正在阅读 ios 4 的核心音频,目的是构建一个小测试应用程序。 在这一点上,我对所有 api 的研究感到非常困惑。理想情况下,我想知道如何从两个 mp3 中提取一些样本到数组中。 然后在回调循环中
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是无关紧要的,因
我下载了 GNUStep并安装了它,但是我不确定在哪里可以找到 IDE。有谁知道什么程序可以用作 GNUStep IDE/从哪里获取它们?否则,有没有人知道有关如何创建和编译基本 GNUStep 程序
我正在尝试开始使用 Apache Solr,但有些事情我不清楚。通读tutorial ,我已经设置了一个正在运行的 Solr 实例。我感到困惑的是 Solr 的所有配置(架构等)都是 XML 格式的。
请问有没有关于如何开始使用 BruTile 的文档? 我目前正在使用 SharpMap,我需要预缓存切片以加快进程 最佳答案 我今天正在研究这个:)Mapsui项目site严重依赖 SharpMap
尽我所能,我无法让 CEDET 做任何事情。 Emacs 24.3。我下载了最新的 CEDET 快照。我从他的底部(不是这样)Gentle Introduction 中获取了 Alex Ott 的设置
我是一名优秀的程序员,十分优秀!