标准IO:库函数
- 一、基本概念
- 1.文件类型
- 2.标准I/O介绍
- 3.流的概念
- 4.文本流和二进制流
- 5.流的缓冲类型
- 6.标准I/O流(stdin、stdout、stderr)
- 二、标准I/O函数
- 1.fopen、fclose、errrno、strerror、perror(打开、关闭文件,输出错误码信息)
- 2.fgetc、fputc、getchar、putchar(读写一个字符)
- 3.fgets、fputs、gets、puts(读写一行)
- 4.fread、fwrite(读写若干个对象)
- 5.feof、ferror(判断文件是否结束或出错)
- 6.sprintf、snprintf、fprintf(格式化输出到内存、文件)
- 7.time、localtime(获取系统时间,将系统时间转为本地时间)
- 8.fflush(刷新缓冲区)
- 9.fseek、rewind、ftell(定位文件指针)
- 10.freopen(重定向输入输出流)
- 三、示例代码
- 1.fgetc(统计文本文件字符数)
- 2.fputc(将a~z写入文件)
- 3.fgets(标准输入流写入buff)
- 4.fputs(将内存数据输出到标准输出流)
- 5.fread、fwrite(二进制文件读写)
- 6.fflush(刷新流,刷新缓冲区)
- 7.ftell、fseek、rewind(定位流指针)
- 8.fprintf、sprintf(格式化输出数据到文件、内存,常用sprintf)
- 9.fscanf、sscanf(将文件、内存数据格式化输入,可用作解析字符串)
- 四、案例源码
- 1.复制文件1
- 2.统计文本文件行数
- 3.复制文件2
- 4.获取文件长度
- 5.按指定格式打印时间
一、基本概念
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 |
二、标准I/O函数
1.fopen、fclose、errrno、strerror、perror(打开、关闭文件,输出错误码信息)
FILE *fopen(const char *pathname, const char *mode);
功能:打开文件(标准IO)
参数:
@pathname:想要打开文件的路径及名字 "./hello.txt" "/home/linux/1.c"
@mode:打开文件的方式 "a" "a+" "w" "w+" "r" "r+"
r 以只读的方式打开文件,将光标定位到文件的开头
r+ 以读写的方式打开文件,将光标定位到文件的开头
w 以只写方式打开文件,如果文件存在就清空,如果文件不存在就创建,将光标定位到开头
w+ 以读写方式打开文件,如果文件存在就清空,如果文件不存在就创建,将光标定位到开头
a 以追加的方式打开文件,如果文件不存在就创建,如果文件存在不会清空,将光标定位到结尾
a+ 以读和追加的方式打开文件,如果文件不存在就创建,读光标在开头,写光标在结尾(光标就一个)
返回值:成功返回文件指针,失败返回NULL,置位错误码errno
int fclose(FILE *stream);
功能:关闭文件
参数:
@stream:文件指针
返回值:成功返回0,失败返回EOF(-1),置位错误码 //#define EOF (-1)
#include <errno.h>
extern int errno;
errno 存放错误码
#include <string.h>
char *strerror(int errnum);
功能:将错误码转换为错误信息
参数:
@errnum:错误码
返回值:错误信息的字符串
void perror(const char *s);
功能:打印错误信息
参数:
@s:用户的附加信息
返回值:无
2.fgetc、fputc、getchar、putchar(读写一个字符)
int fgetc(FILE *stream);
功能:从文件中读取一个字符(光标自动向后移动)
参数:
@stream:文件指针
返回值:成功返回读取到的字符的ASCII,读取到结尾或者遇到错误就返回EOF
int fputc(int c, FILE *stream);
功能:向文件中写入一个字符(光标自动向后移动)
参数:
@c:字符的ascii的值 ‘c’ 65
@stream:文件指针
返回值:成功返回读取到的字符的ASCII,失败返回EOF
int getchar(void);
getchar()等同于fgetc(stdin)
int putchar(int c);
putchar(c)等同于fputc(ch, stdout)
3.fgets、fputs、gets、puts(读写一行)
char *fgets(char *s, int size, FILE *stream);
功能:从文件中向s指向的内存中读取字符串,最多读size-1个字符(最后一个用于存‘\0’)。
fgets遇到EOF或者换行符的时候就会停止,如果遇到换行符停止的,换行符也会被存储到s中。
参数:
@s:指向存储字符的首地址
@size:想要读取字符的个数
@stream:文件指针
返回值:成功返回s,失败返回NULL
int fputs(const char *s, FILE *stream);
功能:将s中的字符串写入到文件中
参数:
@s:被写字符串的首地址
@steam:文件指针
返回值:成功返回大于0的值,失败返回EOF
char *gets(char *s);
功能:gets从标准输入stdin读字符串到s
返回值:成功返回时s,遇到'\n'或已输入size-1个字符时返回,总是包含'\0',到文件末尾或出错返回NULL
gets不推荐使用,容易造成缓冲区溢出
int puts(const char *s);
功能:puts将缓冲区s中的字符串输出到stdout,并追加'\n'
返回值:成功时返回输出的字符个数,失败返回EOF
4.fread、fwrite(读写若干个对象)
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:从stream中读取nmemb项数据,每一项的大小是size,将它们存到ptr
参数:
@ptr:存储读取到数据的首地址
@size:每一项的大小
@nmemb:项目的个数
@stream:文件指针
返回值:成功返回读取到的项目的个数,如果小于项目的个数就是错误或者到文件的结尾了。
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
功能:将ptr中的数据写入到stream中,写nmemb向,每一项的大小是size
参数:
@ptr:被写数据的首地址
@size:每一项的大小
@nmemb:项目的个数
@stream:文件指针
返回值:成功返回项目的个数,失败返回小于项目的个数。
5.feof、ferror(判断文件是否结束或出错)
fread返回值无法区分是到达了文件的结尾还是错误发生了,调用者必须通过feof或者ferror函数来判断。
int feof(FILE *stream);
功能:判断是否读取到了文件的结尾,如果到了文件的结尾将返回真
参数:
@stream:文件指针
返回值:如果到了文件的结尾返回真,如果没有到文件结尾返回假
int ferror(FILE *stream);
功能:如果在读文件的时候发生了错误,这个函数返回真
参数:
@stream:文件指针
返回值:如果发生了错误返回真,如果没有发生错误返回假
6.sprintf、snprintf、fprintf(格式化输出到内存、文件)
int sprintf(char *str, const char *format, ...);
功能:将format控制格式的内容写到str对应的内存中(不会向终端显示)
参数:
@str:内存地址
@format:和printf的参数完全相同
返回值:成功返回格式化的字符的个数,失败返回负数
int snprintf(char *str, size_t size, const char *format, ...);
功能:将format控制格式的内容写到str对应的内存中(不会向终端显示)
参数:
@str:内存地址
@size:最多格式化size个字符,其中还包括一个'\0'
@format:和printf的参数完全相同
返回值:成功返回格式化的字符的个数,失败返回负数
int fprintf(FILE *stream, const char *format, ...);
功能:将控制格式格式化的字符串写入到文件中
参数:
@stream:文件指针
@format:控制格式
返回值:成功返回格式化的字符的个数,失败返回负数
7.time、localtime(获取系统时间,将系统时间转为本地时间)
#include <time.h>
time_t time(time_t *tloc);
功能:获取自1970-01-01 00:00:00到当前的秒钟数
参数:
@tloc:NULL
返回值:成功返回秒钟数,失败返回-1,并置位错误码
struct tm *localtime(const time_t *timep);
功能:将time_t的秒钟转换为tm的结构体(结构体中包含年、月、日...)
参数:
@timep:秒钟变量的地址
返回值:成功返回tm结构体指针,失败返回NULL,并置位错误码
struct tm {
int tm_sec; /* Seconds (0-60) */
int tm_min; /* Minutes (0-59) */
int tm_hour; /* Hours (0-23) */
int tm_mday; /* Day of the month (1-31) */
int tm_mon; /* Month (0-11) */ //+1
int tm_year; /* Year - 1900 */ //+1900
int tm_wday; /* Day of the week (0-6, Sunday = 0) */ //周几
int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */ //这一年中的第几天
int tm_isdst; /* Daylight saving time */ //夏令时
};
8.fflush(刷新缓冲区)
int fflush(FILE *fp);
功能:将流缓冲区里的数据写入到实际的文件,Linux下只能刷新输出缓冲区
参数:
@fp:文件指针
返回值:成功返回0,失败返回EOF
9.fseek、rewind、ftell(定位文件指针)
int fseek(FILE *stream, long offset, int whence);
功能:设置光标的位置
参数:
@stream:文件指针
@offset:光标的偏移
>0 向后偏移
=0 不偏移
<0 向前偏移
@whence:从那个位置偏移
SEEK_SET //从开头开始偏移
SEEK_CUR //从当前位置偏移
SEEK_END //从结尾的位置偏移
返回值:成功返回0,失败返回-1置位错误码
eg:
fseek(fp,0,SEEK_END); //将光标定位到文件的结尾
fseek(fp,50,SEEK_SET);//将光标定位到第50个字节的位置
fseek(fp,-5,SEEK_CUR);//将光标从当前位置向前偏移5个字节
1. 文件a模式打开时,函数fseek无效
2. rewind(fp)相当于fseek(fp, 0, SEEK_SET)
3. 这3个函数只适用于2G以下的文件
void rewind(FILE *stream);
功能:将光标恢复到文件的开头(rewind = fseek(stream, 0, SEEK_SET))
参数:
@stream:文件指针
返回值:无
long ftell(FILE *stream);
功能:返回光标到文件开头的字节数
参数:
@stream:文件指针
返回值:成功返回字节数,失败返回-1置位错误码
10.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(统计文本文件字符数)
#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;
}