1.用 < 和 > 做重定向
file.c
#include<stdio.h>
int main(int argc, const char *argv)
{
int num;
int i1 = scanf("%i", &num);
int i2 = printf("%d\n", num);
printf("%d:%d\n", i1, i2);
return 0;
}
2. API
- FILE* fopen(const char* restrict path, const char* restrict mode);
- mode:
- r:打开只读
- r+:打开读写,从文件头开始
- w:打开只写。如果不存在则新建,如果存在则清空
- w+:打开读写。如果不存在则新建,如果存在则清空
- a:打开追加。如果不存在则新建,如果存在则从文件尾开始
- ..x:只新建,如果文件已存在则不能打开
- mode:
- int fclose(FILE *stream);
- fscanf(FILE*, …);
- fprintf(FILE*, …);
#include<stdio.h>
int main(int argc, const char *argv)
{
FILE *fp = fopen("text.txt", "r");// text.txt的内容是:12345
if(fp)
{
int num;
fscanf(fp, "%d", &num);
printf("%d\n", num);//输出12345
fclose(fp);
} else {
printf("无法打开文件\n");
}
return 0;
}
3.文本文件与二进制文件
- 所有文件最终都是二进制的
- 文本文件是用最简单的方式可以读写的文件
- more、tail
- cat
- vi
- 二进制文件是需要专门的程序来读写的文件
- 文本文件的输入输出是格式化可能经过转码的
3.1 Unix与Windows对文件的选取
- Unix喜欢用文本文件做数据存储和程序配置
- 交互式终端的出现使得人们喜欢用文本和计算机交互
- Unix的shell提供了一些读写文本的小程序
- Windows喜欢用二进制文件
- PC刚开始的时候能力有限,DOS的能力更有限,二进制更接近底层
3.2 优缺点
文本:
- 优势:方便人类读写,而且跨平台
- 劣势:程序输入输出要经过格式化,开销大
二进制
- 优势:程序读写快
- 劣势:人类读写困难,不能跨平台
- int的大小不一致,大小端的问题
3.3 文件的应用
- 配置
- Unix用文本,Windows用注册表
- 数据
- 稍微有点量的数据都要存储到数据库中
- 媒体
- 媒体只能是二进制的
- 现实情况,程序通过第三方库来读写文件,很少直接读写二进制文件
3.4 二进制文件的读写
- size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
- size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
- 返回的是成功读写的字节数
- FILE指针是最后一个参数
- nitem是用来说明这次读写几个结构变量,二进制文件的读写一般都是通过一个结构变量的操作来进行的
student.h
#ifndef _STUDENT_H_
#define _STUDENT_H_
typedef struct _student{
char name[20];
int gender;
int age;
} Student;
#endif
main.c
#include <stdio.h>
#include "student.h"
void inputList(Student aStu[], int number);
int save(Student aStu[], int number);
int main(int argc, char *argv[]) {
int number = 0;
printf("请输入学生的数量:");
scanf("%d", &number);
Student aStu[number];
inputList(aStu, number);
if(save(aStu, number)){
printf("保存成功\n");
} else {
printf("保存失败\n");
}
return 0;
}
void inputList(Student aStu[], int number)
{
char format[20];
sprintf(format, "%%%ds", 19);
int i;
for(i = 0; i < number; i++){
printf("第%d个学生:\n", i);
printf("\t姓名:");
scanf(format, aStu[i].name);
printf("\t性别(0-男,1-女,2-其他)");
scanf("%d", &aStu[i].gender);
printf("\t年龄:");
scanf("%d", &aStu[i].age);
}
}
int save(Student aStu[], int number)
{
int ret = -1;
FILE *fp = fopen("Student.data", "w");
if(fp){
ret = fwrite(aStu, sizeof(Student), number, fp);
fclose(fp);
}
return ret == number;
}
student.data中保存的是二进制
3.5 在文件中定位
- long ftell(FILE *stream);
- int fseek(FILE *stream, long offset, int whence);
- whence:
- SEEK_SET:从头开始
- SEEK_CUR:从当前位置开始
- SEEK_END:从尾开始
- whence:
student.h
int index = 0;
main.c
#include <stdio.h>
#include "student.h"
void read(FILE *fp, int index);
int main(int argc, char *argv[]) {
FILE *fp = fopen("student.data", "r");
if(fp){
fseek(fp, 0L, SEEK_END);
long size = ftell(fp);
int number = size / sizeof(Student);
printf("有%d个数据,你要看第几个:", number);
int index = 0;
scanf("%d", &index);
read(fp, index - 1);
fclose(fp);
}
return 0;
}
void read(FILE *fp, int index)
{
fseek(fp, index*sizeof(Student), SEEK_SET);
Student stu;
if(fread(&stu, sizeof(Student), 1, fp) == 1){
printf("第%d个学生:", index + 1);
printf("\t姓名:%s\n", stu.name);
printf("\t性别:");
switch(stu.gender){
case 0:
printf("男\n");
break;
case 1:
printf("女\n");
break;
case 2:
printf("其他\n");
break;
}
printf("\t年龄:%d\n", stu.age);
}
}
tips
- student.data这种二进制文件不具有可移植性
- 在int位32位的机器上写成的数据文件 不能直接在int为64位的机器上正确读写
- 更好的方案是用文本