C语言的文件操作

读写文件与printf、scanf关联

printf : 将数据写出到屏幕 stdin 标准输入 –> 0
scanf : 从键盘获取用户数据 stdout 标准输出 –> 1
perror : 将错误信息写出到屏幕 stderr 标准错误 –> 2

系统文件:
标准输入、标准输出。标准错误。
会在程序加载到内存后运行时,由操作系统自动打开,自动关闭,

文件指针和普通指针的区别

  • 定义文件指针
    1
    2
    File *fp; // 一定是野指针。
    通过fopen将fp初始化为有效指针。

文件分类:

设备文件

= 屏幕、键盘等。

磁盘文件

  • 各种文件
  • 在计算机内数据以各种格式的文件存储。

文件操作

  • 打开文件 fopen
    1
    2
    3
    4
    5
    6
    FILE *fopen( const char *filename, const char *mode );
    // 1、文件路径
    // 2、打开文件的方式 读/写
    // 返回值:执行成功打开的文件的 “文件指针”
    // 成功:指针。
    // 失败:NULL。

文件打开的方式

r : 读文件,若文件存在,则返回成功指针;若文件不存在,报错。
w : 写文件,若文件存在,则清空文件,若文件不存在,则创建文件
a : 追加打开。
r+: 读写方式打开文件,若文件存在,则返回成功指针;若文件不存在,报错。
w+: 读写方式打开文件,若文件存在,则清空文件,若文件不存在,则创建文件
a+: 追加打开。
b : 表示打开的是一个二进制文件。

写方式打开文件:
写方式打开文件:

  • 对文件进行读写操作:
    • 按字符读写文件:fputc(), fgetc();
    • 按行读写文件。 fgets(), fputs();
    • 找文件结束标记。(EOF)
1
2


  • 关闭文件,
    1
    2
    3
    int fclose( FILE *stream );
    // 1、传入文件指针,fopen的指针值。
    // 返回值:success:0,failed:-1.

文件访问路径

绝对路径


从系统根目录位置起始,描述的文件访问路径。


相对路径


相对于当前的工作目录。不纠结编译工具。


fputc

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

fgetc

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

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main0201(int argc, char *argv[]) {

FILE *fp = fopen("abc.txt","w");

// 输出到文件26个字母。
for (int i = 65; i < 91; i++) {
fputc(i, fp);
}

fclose(fp);
FILE *fp2 = fopen("abc.txt","r");


char c = 0;
for (int j = 0; j < 26; j++) {
c = (char) fgetc(fp2);
printf("%c",c);
}

return 0;
}

文件结束标记:值为-1

feof函数


技能判断文本文件,也能判断二进制文件的结尾,-1也可以读出来。
要使feof函数生效,必须在feof函数调用前进行读文件操作。


fgets


从文件中读取字符串数据,保存在存储空间中。


  • 一次读一行,一行内默认\n结束。会读取到\n。
  • 当char *str【n】空间不足,则预留\0的位置,实际读到 n-1个字符。
1
2
3
4
5
char * fgets(char * str, int size, FILE * stream);
// 1、存储读到的数据空间
// 2、空间大小
// 3、数据来源的文件。
// 4、返回值:成功:读到的字符串/失败:NULL/读到文件末尾:NULL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main0301 (int argc, char *argv[]) {

// 文件指针
FILE *fp = fopen("/Users/lele/Desktop/default.txt", "r");

// 判空
if (!fp){
perror("error");
return -1;
}

// 定义存储大小
int sizenum = sizeof(char)*4096;
char *str = malloc((size_t) sizenum);

// 字符串置空
memset(str, 0, sizenum);

// 逐行打印文件内容
while (!feof(fp)) {
fgets(str, sizenum, fp);
printf("%s", str);
}

// 释放并置空malloc的内存
free(str);
str = NULL;

fclose(fp);

return 0;
}

fputs


将一个字符串的数据写入到文件中,


1
2
3
4
5
char * fgets(char * str, int size, FILE * stream);
// 1、存储读到的数据空间
// 2、空间大小
// 3、数据来源的文件。
// 4、返回值:成功:读到的字符串/失败:NULL/读到文件末尾:NULL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

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

int main0401(int argc, char *argv[]) {

FILE *fp = fopen("./hello.c", "w");

if (!fp){
perror("error");
}

int sizenum = sizeof(char);

char *buf = malloc((size_t) sizenum);

while (1){

memset(buf, 0, sizenum);

scanf("%[^\n]", buf);
getchar();

if (strcmp(buf, ":quit") == 0){
break;
}

strcat(buf, "\n");

fputs(buf, fp);
}

free(buf);
buf = NULL;

fclose(fp);

return 0;

fprintf

printf sprintf fprintf
scanf sscanf fscanf

键盘、屏幕 string file

共性:都有格式串“%d, %s, %c, %x…”,变参

1
int fprintf( FILE *stream, const char *format, ... );
  • 参数一:待写入文件的指针
  • 参数二:格式串
  • 变参:对应格式串的数据
  • 返回值: 成功:成功写入字符串的个数/失败:-1

fscanf

1
int scanf( const char          *format, ... );​
  • 参数一:待写入文件的指针
  • 参数二:格式串
  • 变参:对应格式串的数据
  • 返回值: 成功:成功写入字符串的个数/失败:-1

特性:
fscanf函数每次调用时,会判断下一次参数是否满足匹配条件,若不满足,提前返回


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/**
* Powered by Jetbrains Clion.
* Created by 忘了.
* Date: 2018/5/28.
* FileName: 0x01_fscanf_sprintf.c.
*/

//***** Code is coming! *****//

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



void random2file(){

srand(time(NULL));

FILE *fp = fopen("num.txt", "w");
if (!fp) {
perror("fopen error");
}

for (int i = 0; i < 100; i++) {
fprintf(fp, "%d\n", rand() % 100);
}

fclose(fp);
}

void BubbleSort(int *arr, int n){

int tmp = 0;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j+1]){
tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;

}
}
}

}

void file2arr(){

int num = 0, i = 0;

FILE *fp = fopen("num.txt", "r");
if (!fp) {
perror("fopen error");
}

int *arr = malloc(sizeof(int)*1024);

while (1) {

fscanf(fp, "%d\n", &num);
arr[i] = num;
i++;

if (feof(fp)){
break;

}

}

printf("i = %d\n", i);
BubbleSort(arr, i);

fclose(fp);


for (int j = 0; j < i; j++) {
printf("%d\n", arr[j]);
}

fp = fopen("num.txt", "w");

for (int j = 0; j < i; j++) {
fprintf(fp, "%d\n", arr[j]);
}


free(arr);
arr = NULL;
fclose(fp);

}

int main(int argc, char *argv[]) {

random2file();
file2arr();

return 0;
}

Windows二进制的读写


二进制读写的参数,只在Windows下用b权限,在linux下不需要。


fread

fwrite

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <stdio.h>

enum {
SIZE = 5
};

int main(int argc, char *argv[]) {

double a[SIZE] = {1.21, 2.32, 3.23, 4.34, 5.45};

FILE *fp = fopen("test.bin", "wb");

// Write double array to file.
fwrite(a, sizeof(*a), SIZE, fp);
fclose(fp);

// Read file
double b[SIZE];
fp = fopen("test.bin", "rb");

// Return success write to file's number
size_t ret_code = fread(b, sizeof(*b), SIZE, fp);

if (ret_code == SIZE) {
puts("Read successfully!, This array contents:");
for (int i = 0; i < SIZE; ++i) {
printf("%lf ", b[i]);
}
putchar('\n');
} else {
// Error handling
if (feof(fp))
printf("Error reading test.bin: unexpected end of file\n");
else if (ferror(fp)) {
perror("Error reading test.bin");
}
}

return 0;
}

文件的随机读写

fseek

1
2
fseek()
int fseek(FILE *stream, long offset, int whence);
  • 参数:
    • 参数1:文件指针
    • 参数2:偏移量(正、负))
    • 参数3:偏移的其实文职:SEEK_SET:文档开头
      SEEK_CUR:当前位置
      seek_END:文件结尾
      
    • 返回值:
      • 成功:0
      • 失败:-1

ftell


光标到文件开头的偏移量


1
long ftell(FILE *stream)
  • 返回值:
    光标到文件开头的偏移量。

rewind


将光标移动至文件起始位置。


1
void rewind(FILE *stream)

更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


/**
* 按照字符读写文件
*/
static void test01() {
//写文件
FILE *fp = fopen("test", "w+");

if (fp == NULL) {
return;
}

char str[] = "Test0101001";

for (int i = 0; i < strlen(str); i++) {
fputc(str[i], fp);
}


fclose(fp);

// 读文件
FILE *fp_r = fopen("test", "r");

if (fp_r == NULL) {
return;
}

int ch;
while ((ch = fgetc(fp_r)) != EOF) {
printf("%c", ch);
}
fclose(fp_r);

}


// 按照行读写文件
static void test02() {

FILE *fp_w = fopen("test2", "w+");

if (fp_w == NULL) {
return;
}

char *buf[] = {
"锄禾日当午\n",
"汗滴禾下土\n",
"谁知盘中餐\n",
"粒粒皆辛苦\n"};

for (int i = 0; i < 4; i++) {
fputs(buf[i], fp_w);
}

fclose(fp_w);


FILE *fp_r = fopen("test2", "r");

if (fp_r == NULL) {
return;
}

while (!feof(fp_r)) {

char buf2[1024] = {0};

fgets(buf2, 1024, fp_r);

printf("%s", buf2);

}

fclose(fp_r);


}

typedef struct _HERO {
char name[64];
int age;
} Hero;

// 按照块读写文件
static void test03() {

FILE *fp_w = fopen("test03", "wb");

if (fp_w == NULL) {

perror("Failed");
return;

}

Hero hero[] = {
{"a", 10},
{"b", 20},
{"c", 34},
{"d", 55}
};


int heroLen = (int) (sizeof(hero) / sizeof(hero[0]));

for (int i = 0; i < heroLen; i++) {
fwrite(&hero[i], sizeof(Hero), 1, fp_w);
}

fclose(fp_w);


FILE *fp_r = fopen("test03", "rb");

if (fp_r == NULL) {

perror("Failed");
return;

}


Hero tmp[4];
for (int i = 0; i < 4; i++) {
fread(&tmp[i], sizeof(Hero), 1, fp_r);
printf("%s, %d\n", tmp[i].name, tmp[i].age);
}

fclose(fp_w);
}

// 利用格式化读写
static void test04() {

FILE *f_write = fopen("./test04", "w");
if (f_write == NULL) {
return;
}

fprintf(f_write, "hello world %d年 %d月 %d日", 2018, 7, 5);

fclose(f_write);

FILE *f_read = fopen("./test04", "r");
if (f_read == NULL) {
return;
}

char buf[1024] = {0};
while (!feof(f_read)) {
fscanf(f_read, "%s", buf);
printf("%s\n", buf);
}

fclose(f_read);
}


int main03(int argc, char *argv[]) {

// test01();
// test02();
// test03();
test04();

return 0;