一、基本概念
1.文件类型
概念:一组相关数据的有序集合
文件类型:
- 常规文件 r
- 目录文件 d
- 字符设备文件 c
- 块设备文件 b
- 管道文件 p
- 套接字文件 s
- 符号链接文件 l
2.标准I/O介绍
标志I/O由ANSI C标准定义,主流操作系统上都实现了C库
标准I/O通过缓冲机制减少系统调用,实现更高的效率
3.流的概念
FILE:
标准I/O用一个结构体类型来存放打开的文件的相关信息
标准I/O的所有操作都是围绕FILEl来进行
流(stream):
FILE又被称为流(stream)
文本流/二进制流
4.文本流和二进制流
windows
二进制流:换行符 <—> ‘\n’
文本流:换行符 <—> ‘\r’‘\n’
Liniux
换行符 <—> ‘\n’
5.流的缓冲类型
全缓冲
当流的缓冲区无数据或无空间时才执行实际I/O操作
行缓冲
当输入和输出中遇到换行符(‘\n’)时,进行I/O操作
当流和一个终端关联时,典型的行缓冲
无缓冲
数据直接写入文件,流不进行缓冲
6.标准I/O流(stdin、stdout、stderr)
标准I/O预定义3个流,程序运行时自动打开
标准输入流 | 0 | STDIN_FILENO | stdin |
标准输出流 | 1 | STDOUT_FILENO | stdout |
标准错误流 | 2 | STDERR_FILENO | stderr |
二、流的操作
1.打开流(fopen)
(1)mode参数(r、r+、w、w+、a、a+)
(2)处理错误信息(perror、strerror)
(3)重定向输入输出流(freopen)
2.关闭流(fclose)
3.示例代码
(1)fopen、perror、strerror、fclose
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, const char **argv)
{
FILE *fp;
fp = fopen("1.txt", "r+");
if (fp == NULL) {
perror("fopen");
printf("fopen: %s\n", strerror(errno));
return -1;
}
fclose(fp);
printf("end!\n");
return 0;
}
(2)freopen
#include <stdio.h>
int main(int argc, const char **argv)
{
if (freopen("1.txt", "w", stdout) == NULL) {
perror("freopen");
return -1;
}
printf("stdout --> 1.txt\n");
fclose(stdout);
printf("end!\n");
return 0;
}
三、读写流
1.按字符输入(fgetc、getc、getchar)
2.按字符输出(fputc、putc、putchar)
3.按行输入(gets、fgets)
4.按行输出(puts、fputs)
5.按对象读写(fread、fwrite)
6.刷新流(fflush)
7.定位流指针(ftell、fseek、rewind)
注意事项
- 文件a模式打开时,函数fseek无效
- rewind(fp)相当于fseek(fp, 0, SEEK_SET)
- 这3个函数只适用于2G以下的文件
8.判断流是否出错和结束(ferror、feof)
9.格式化输出(printf、fprintf、sprintf)
四、示例代码
1.fgetc(统计文本文件字符数)
#include <stdio.h>
int main(int argc, const char **argv)
{
int ch;
FILE *fp;
int count = 0;
if (argc < 2) {
printf("Usage: %s <file>\n", argv[0]);
return -1;
}
//1
ch = fgetc(stdin);
if (ch == EOF) {
perror("fgetc");
return -1;
}
printf("ch is %c\n", ch);
//2
if ((fp = fopen(argv[1], "r")) == NULL) {
perror("fopen");
return -1;
}
while ((ch = fgetc(fp)) != EOF) {
count++;
}
printf("%s total %d bytes!\n", argv[1], count);
fclose(fp);
return 0;
}
2.fputc(将a~z写入文件)
#include <stdio.h>
int main(int argc, const char **argv)
{
int ch;
int ret;
FILE *fp;
if (argc < 2) {
printf("Usage: %s <file>\n", argv[0]);
return -1;
}
//1
ret = fputc('a', stdout);
if (ret == EOF) {
perror("fputc");
return -1;
}
putchar('\n');
//2
if ((fp = fopen(argv[1], "w")) == NULL) {
perror("fopen");
return -1;
}
for (ch = 'a'; ch <= 'z'; ch++) {
fputc(ch, fp);
}
fclose(fp);
return 0;
}
3.fgets(标准输入流写入buff)
#include <stdio.h>
#define N 6
int main(int argc, char **argv)
{
char buff[N];
fgets(buff, N, stdin);
printf("%s", buff);
return 0;
}
4.fputs(将内存数据输出到标准输出流)
#include <stdio.h>
int main(int argc, char **argv)
{
puts("hello world"); //加换行
char buff[] = "hello world\n"; //不加换行
fputs(buff, stdout);
return 0;
}
5.fread、fwrite(二进制文件读写)
#include <stdio.h>
#include <string.h>
struct stu {
char name[15];
int age;
char sex[10];
};
int main(int argc, char **argv)
{
FILE *fp;
struct stu s1,s2;
int ret;
if ((fp = fopen("1.bin", "w+")) == NULL) {
perror("fopen");
return -1;
}
strcpy(s1.name, "tanpeng");
s1.age = 21;
strcpy(s1.sex, "male");
ret = fwrite(&s1, sizeof(s1), 1, fp);
if (ret == EOF) {
perror("fwrite");
return -1;
}
fclose(fp);
if ((fp = fopen("1.bin", "r+")) == NULL) {
perror("fopen");
return -1;
}
ret = fread(&s2, sizeof(s2), 1, fp);
if (ret == EOF) {
perror("fread");
return -1;
}
printf("name:%s age:%d sex:%s\n", s2.name, s2.age, s2.sex);
fclose(fp);
return 0;
}
6.fflush(刷新流,刷新缓冲区)
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
FILE *fp;
int ret;
if ((fp = fopen("1.bin", "a+")) == NULL) {
perror("fopen");
return -1;
}
ret = fwrite("abcdef", 6, 1, fp);
if (ret == EOF) {
perror("fwrite");
return -1;
}
fflush(fp);
while(1) {
sleep(1);
}
fclose(fp);
return 0;
}
7.ftell、fseek、rewind(定位流指针)
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
FILE *fp;
int ret;
if ((fp = fopen("1.bin", "w")) == NULL) {
perror("fopen");
return -1;
}
ret = fwrite("abcdef", 6, 1, fp);
if (ret == EOF) {
perror("fwrite");
return -1;
}
printf("start fp:%d\n", (int)ftell(fp));
ret = fseek(fp, -4, SEEK_CUR);
ret = fwrite("ss", 2, 1, fp);
if (ret == EOF) {
perror("fwrite");
return -1;
}
printf("fseek fp:%d\n", (int)ftell(fp));
rewind(fp);
ret = fwrite("rr", 2, 1, fp);
if (ret == EOF) {
perror("fwrite");
return -1;
}
printf("rewind fp:%d\n", (int)ftell(fp));
fclose(fp);
return 0;
}
8.fprintf、sprintf(格式化输出数据到文件、内存,常用sprintf)
#include <stdio.h>
int main(int argc, char **argv)
{
FILE *fp;
char buff[40];
int year = 2022;
int month = 8;
int day = 7;
if ((fp = fopen("1.txt", "w+")) == NULL) {
perror("fopen");
return -1;
}
fprintf(fp, "%d-%d-%d\n", year, month, day);
sprintf(buff, "%d-%d-%d", year, month, day);
printf("%s\n", buff);
fclose(fp);
return 0;
}
9.fscanf、sscanf(将文件、内存数据格式化输入,可用作解析字符串)
#include <stdio.h>
int main(int argc, char **argv)
{
FILE *fp;
char buff[40];
int year = 2022;
int month = 8;
int day = 7;
int fyear,fmonth,fday;
int syear,smonth,sday;
//1.fscanf
if ((fp = fopen("1.txt", "w+")) == NULL) {
perror("fopen");
return -1;
}
fprintf(fp, "%d-%d-%d", year, month, day);
rewind(fp);
fscanf(fp, "%d-%d-%d", &fyear, &fmonth, &fday);
printf("after fscanf:\n");
printf("%d,%d,%d\n", fyear, fmonth, fday);
//2.sscanf
sprintf(buff, "%d-%d-%d", year, month, day);
printf("%s\n", buff);
sscanf(buff, "%d-%d-%d", &syear, &smonth, &sday);
printf("after sscanf:\n");
printf("%d,%d,%d\n", syear, smonth, sday);
fclose(fp);
return 0;
}
五、案例源码
1.复制文件1
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fps, *fpd;
int ch;
if (argc < 3) {
printf("Usage : %s <src_file> <dst_file>\n", argv[0]);
return -1;
}
if ((fps = fopen(argv[1], "r")) == NULL) {
perror("fopen");
return -1;
}
if ((fpd = fopen(argv[2], "w")) == NULL) {
perror("fopen");
return -1;
}
while ((ch = fgetc(fps)) != EOF) {
fputc(ch, fpd);
}
fclose(fps);
fclose(fpd);
return 0;
}
2.统计文本文件行数
#include <stdio.h>
#include <string.h>
#define N 64
int main(int argc, char *argv[])
{
FILE *fp;
int line = 0;
char buf[N];
if (argc < 2) {
printf("Usage: %s <file>\n", argv[0]);
return -1;
}
if ((fp = fopen(argv[1], "r")) == NULL) {
printf("fopen error\n");
return -1;
}
while (fgets(buf, N, fp) != NULL) {
if (buf[strlen(buf)-1] == '\n') line++;
}
printf("the line of %s is %d\n", argv[1], line);
return 0;
}
3.复制文件2
#include <stdio.h>
#define N 64
int main(int argc, char *argv[])
{
FILE *fps, *fpd;
int buf[N];
int n;
if (argc < 3) {
printf("Usage : %s <src_file> <dst_file>\n", argv[0]);
return -1;
}
if ((fps = fopen(argv[1], "r")) == NULL) {
perror("fopen src file");
return -1;
}
if ((fpd = fopen(argv[2], "w")) == NULL) {
perror("fopen dst file");
return -1;
}
while ((n = fread(buf, 1, N, fps)) > 0) {
fwrite(buf, 1, n, fpd);
}
fclose(fps);
fclose(fpd);
return 0;
}
4.获取文件长度
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp;
if ((fp = fopen("test.txt", "r+")) == NULL) {
perror("fopen");
return -1;
}
fseek(fp, 0, SEEK_END);
printf("length is %ld\n", ftell(fp));
return 0;
}
5.按指定格式打印时间
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
int main()
{
FILE *fp;
int line = 0;
char buf[64];
time_t t;
struct tm *tp;
if ((fp = fopen("test.txt", "a+")) == NULL) {
perror("fopen");
return -1;
}
while (fgets(buf, 64, fp) != NULL)
{
if (buf[strlen(buf)-1] == '\n') line++;
}
while ( 1 )
{
time(&t);
tp = localtime(&t);
fprintf(fp, "%02d, %d-%02d-%02d %02d:%02d:%02d\n", ++line, tp->tm_year+1900, tp->tm_mon+1,
tp->tm_mday, tp->tm_hour, tp->tm_min, tp->tm_sec);
fflush(fp);
sleep(1);
}
return 0;
}