赞
踩
文件是数据源的一种,最主要的作用是保存数据。
在操作系统中,为了统一对各种硬件的操作,简化接口,不同的硬件设备也都被看成一个文件。对这些文件的操作,等同于对磁盘上普通文件的操作。例如:
常见硬件设备所对应的文件
我们不去探讨硬件设备是如何被映射成文件的,大家只需要记住,在C语言中硬件设备可以看成文件,有些输入输出函数不需要你指明到底读写哪个文件,系统已经为它们设置了默认的文件,当然你也可以更改,例如让printf 向磁盘上的文件输出数据。
操作文件的正确流程为:打开文件 --> 读写文件 --> 关闭文件。文件在进行读写操作之前要先打开,使用完毕要关闭。
所谓打开文件,就是获取文件的有关信息,例如文件名、文件状态、当前读写位置等,这些信息会被保存到一个 FILE 类型的结构体变量中。
关闭文件就是断开与文件之间的联系,释放结构体变量,同时禁止再对该文件进行操作。
在C语言中,文件有多种读写方式,可以一个字符一个字符地读取,也可以读取一整行,还可以读取若干个字节。文件的读写位置也非常灵活,可以从文件开头读取,也可以从中间位置读取。
文件(保存在磁盘中)只有加载到内存中才可以进行处理,内存中的数据只有保存到文件(磁盘)中才可以不丢失。在这期间我们把数据在文件到内存中的传递叫做文件流。
文件是数据源的一种,除了文件,还有数据库、网络、键盘等,数据传递到内存也就是保存到C语言的变量(例如整数、字符串、数组、缓冲区等)。我们把数据在数据源和程序(内存)之间传递的过程叫做数据流(Data Stream)。相应的,数据从数据源到程序(内存)的过程叫做输入流(Input Stream),从程序(内存)到数据源的过程叫做输出流(Output Stream)。
(在C语言中)我们根据数据在文件存储形式的不同把文件文件和二进制文件。
打开文件
在C语言中,操作文件之前必须先打开文件;所谓“打开文件”,就是让程序和文件建立连接的过程。
打开文件之后,程序可以得到文件的相关信息,例如大小、类型、权限、创建者、更新时间等。在后续读写文件的过程中,程序还可以记录当前读写到了哪个位置,下次可以在此基础上继续操作。
FILE *fopen( const char *filename, const char *mode );(C99 前)
文件打开方式
调用 fopen() 函数时必须指明读写权限,但是可以不指明读写方式(此时默认为"t")。
读写权限和读写方式可以组合使用,但是必须将读写方式放在读写权限的中间或者尾部(换句话说,不能将读写方式放在读写权限的开头)。例如:
将读写方式放在读写权限的末尾:“rb”、“wt”、“ab”、“r+b”、“w+t”、“a+t”
将读写方式放在读写权限的中间:“rb+”、“wt+”、“ab+”
整体来说,文件打开方式由 r、w、a、t、b、+ 六个字符拼成,各字符的含义是:
关闭文件
文件一旦使用完毕,应该用 fclose() 函数把文件关闭,以释放相关资源,避免数据丢失。fclose() 的用法为:
int fclose( FILE stream )
关闭给定的文件流。冲入任何未写入的缓冲数据到 OS 。舍弃任何未读取的缓冲数据。无论操作是否成功,流都不再关联到文件。若在 fclose 返回后使用指针 stream 的值则行为未定义。
示例
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #define N 100 int main() { FILE* fp; char str[N + 1]; if ((fp = fopen("text.txt", "r")) == NULL) { puts("文件打开失败"); exit(0); } while (fgets(str,N,fp)!=NULL) { printf("%s", str); } fclose(fp); return 0; }
int fgetc( FILE *stream );
int fputc( int ch, FILE *stream );
示例
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <windows.h> #define N 100 int main() { FILE* fp; char ch; if ((fp = fopen("text.txt", "r+")) == NULL) { puts("文件打开失败"); exit(0); } while ((ch = fgetc(fp))!=EOF) { // Sleep(100); putchar(ch); } while ((ch = getchar()) != '\n') { fputc(ch, fp); } fclose(fp); return 0; }
char *fgets ( char *str, int n, FILE *fp );
关于fgets()几点要注意的地方
int fputs( char *str, FILE *fp );
注意:puts()往stdin输出时自带换行
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <windows.h> #define N 100 int main() { FILE* fp; char str[N+1]; if ((fp = fopen("text.txt", "r+")) == NULL) { puts("文件打开失败"); exit(0); } while (fgets(str,N,fp)!=NULL) { //Sleep(100); printf("%s", str); } fclose(fp); return 0; }
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );(C99 前)
size_t fread( void *restrict buffer, size_t size, size_t count,FILE *restrict stream );(C99 起)
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );(C99 前)
size_t fwrite( const void *restrict buffer, size_t size, size_t count, FILE *restrict stream );(C99 起)
返回值:返回成功读写的块数(对象数),也即 count。如果返回值小于 count:
示例
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <assert.h> enum { SIZE = 5 }; int main(void) { int a[SIZE] = { 1, 2, 3, 4, 5 }; FILE* fp1 = fopen("text.txt", "wb"); assert(fp1); int tem = fwrite(a, sizeof(a[0]), SIZE, fp1); printf("成功将%d个数据写入文件\n", tem); fclose(fp1); int b[SIZE]; FILE* fp2 = fopen("text.txt", "rb"); assert(fp2); tem = fread(b, sizeof b[0], SIZE, fp2); fclose(fp2); printf("成功读入%d个数据\n", tem); for (int i = 0; i < SIZE; i++) { printf("%d ", b[i]); } return 0; }
int fscanf ( FILE *fp, char * format, … );
int fprintf ( FILE *fp, char * format, … );
与 scanf() 和 printf() 相比,它们仅仅多了一个 fp 参数。
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<assert.h> #define N 2 struct stu { char name[10]; int num; int age; float score; } boya[N], boyb[N], * pa, * pb; int main() { FILE* fp; fp = fopen("test.txt", "wt+"); assert(fp); pa = boya; for (int i = 0; i < N; i++) { scanf("%s %d %d %f", pa->name, &(pa->num), &(pa->age), &(pa->score)); pa++; } pa = boya; for (int i = 0; i < N; i++) { fprintf(fp, "%s %d %d %f\n", pa->name, pa->num, pa->age, pa->score); pa++; } rewind(fp);//移动文件位置指示器到给定文件流的起始。 pb = boyb; for (int i = 0; i < N; i++) { fscanf(fp, "%s %d %d %f\n", pb->name, &(pb->num), &(pb->age), &(pb->score)); pb++; } pb = boyb; for (int i = 0; i < N; i++) { printf("%s %d %d %f\n", pb->name, pb->num, pb->age, pb->score); pb++; } fclose(fp); return 0; }
前面介绍的文件读写函数都是顺序读写,即读写文件只能从头开始,依次读写各个数据。但在实际开发中经常需要读写文件的中间部分,要解决这个问题,就得先移动文件内部的位置指针,再进行读写。这种读写方式称为随机读写,也就是说从文件的任意位置开始读写。
实现随机读写的关键是要按要求移动位置指针,这称为文件的定位。
void rewind ( FILE *fp );用来将位置指针移动到文件开头
int fseek ( FILE *fp, long offset, int origin );用来将位置指针移动到任意位置
每个位置都用对应的常量来表示:
注意: fseek() 一般用于二进制文件,在文本文件中由于要进行转换,计算的位置有时会出错。
示例:
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<assert.h> //ftell 返回当前的文件位置指示值 // //fgetpos 获取文件位置指示器 // //fseek 将文件位置指示符移动到文件中的指定位置 // //fsetpos 将文件位置指示器移动到文件中的指定位置 // //rewind 将文件位置指示器移动到文件首 #define N 3 struct stu { char name[10]; //姓名 int num; //学号 int age; //年龄 float score; //成绩 }boys[N], boy, * pboys; int main() { FILE* fp; pboys = boys; fp = fopen("test.txt", "w+"); puts("Input data:\n"); for (int i = 0; i < N; i++) { scanf("%s %d %d %f", pboys->name, &pboys->num, &pboys->age, &pboys->score); pboys++; } pboys = boys; fwrite(pboys, sizeof(struct stu), N, fp); rewind(fp); fseek(fp, sizeof(struct stu), SEEK_SET); fread(&boy, sizeof(struct stu), 1, fp); printf("%s %d %d %f", boy.name, boy.num, boy.age, boy.score); fclose(fp); return 0; }
#include "stdio.h" #include "stdlib.h" int main(int arg,char* argv[]){ if(arg!=3){ printf("input error!"); exit(0); } FILE* fpr = fopen(argv[1],"rb"); FILE* fpw = fopen(argv[2],"wb"); if(fpr==NULL||fpw==NULL) return 1; fseek(fpr,0,SEEK_END); int len = ftell(fpr); rewind(fpr); for(int i = 0;i<len;i++){ char ch = fgetc(fpr); fputc(ch,fpw); } fclose(fpr); fpr = NULL; fclose(fpw); fpw = NULL; return 0; }
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
int main(){
FILE* fp = fopen("test.txt", "r");
fseek(fp, 0, SEEK_END);
int len = ftell(fp);
rewind(fp);
printf("文件的长度为:%d", len);//文件中有 0D 0A
return 0;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。