六、关于缓冲区问题
6.1 缓冲区的大小
1> 全缓存:跟自定义文件指针有关的缓冲区,其大小为4096字节
2> 行缓存:跟终端相关的操作使用的是行缓存(stdin、stdout),其大小为1024字节
3> 不缓存:跟标准出错有关的操作是不缓存(stderr),其大小为0
#include
#include
#include
int main(int argc, const char *argv[])
{
//航缓存的大小为1024字节
//如果没有使用行缓存,则默认大小为0
printf("行缓存:%ld\n", stdin->_IO_buf_end - stdin->_IO_buf_base);
//只有完成一次输入时,才能求出行缓存区的大小
int num;
scanf("%d", &num);
printf("stdin行缓存:%ld\n", stdin->_IO_buf_end - stdin->_IO_buf_base);
printf("stdout行缓存:%ld\n", stdout->_IO_buf_end - stdout->_IO_buf_base);
fputs("hello world\n", stderr);
fputs("hello world\n", stderr);
//不缓存的大小为0
printf("不缓存:%ld\n", stderr->_IO_buf_end - stderr->_IO_buf_base);
//全缓存,大小为4096
FILE *fp;
if((fp = fopen("./08file.txt", "w")) == NULL)
{
perror("open file");
return -1;
}
fputc('H', fp);
printf("全缓存:%ld\n", fp->_IO_buf_end - fp->_IO_buf_base);
fclose(fp);
return 0;
}
6.2 缓冲区的刷新时间
1> 行缓存的刷新时机
1、遇到‘\n’会刷新行行缓存
2、程序结束后,自动刷新行缓存
3、当输入输出发生切换时,会刷新行缓存
4、当关闭文件指针时,也会刷新行缓存
5、手动刷新缓存区时,行缓存会进行刷新
6、当缓存区满了后,会自动刷新缓存区
#include
#include
#include
int main(int argc, const char *argv[])
{
/*
printf("hello world"); //没有'\n'不会刷新缓存区
//1、当遇到'\n'时会刷新缓冲器
printf("hello world\n");
while(1);
*/
//2、当程序结束后,会自动刷新行缓存
//printf("hello world");
/*
//3、当输入输出发生切换时,会刷新行缓存
printf("hello world");
int num;
scanf("%d", &num);
while(1);
*/
/*
//4、当关闭文件指针时,也会刷新行缓存
printf("hello world");
fclose(stdout); //关闭文件指针
while(1);
*/
/*
//5、手动刷新缓存区时,行缓存会进行刷新
printf("hello world");
fflush(stdout); //手动刷新缓存区
while(1);
*/
//6、当缓存区满了后,会自动刷新缓存区
for(int i=0; i<1025; i++)
{
printf("%c", 'a');
}
while(1);
return 0;
}
2> 全缓存的刷新时机
1、遇到‘\n’不会刷新全缓存
2、程序结束后,自动刷新全缓存
3、当输入输出发生切换时,会刷新全缓存
4、当关闭文件指针时,也会刷新全缓存
5、手动刷新缓存区时,会刷新全缓存
6、当缓存区满了后,会自动刷新缓存区
#include
#include
#include
int main(int argc, const char *argv[])
{
FILE *fp;
if((fp = fopen("./10file.txt", "w")) == NULL)
{
perror("open file");
return -1;
}
/*
//1、全缓存遇到'\n'不会刷新缓冲区
fputc('A', fp);
fputc('\n', fp);
while(1);
*/
//2、程序运行结束后,会刷新全缓存
//fputc('A', fp);
/*
//3、当你输入输出发生切换时, 会刷新全缓存
fputc('A', fp);
fgetc(fp);
while(1);
*/
/*
//4、当关闭文件时,会刷新全缓存
fputc('A', fp);
fclose(fp);
while(1);
*/
/*
//5、手动刷新缓存区时,也会刷新缓存区
fputc('A', fp);
fflush(fp);
while(1);
*/
//6、缓存区满了,会刷新全缓存
for(int i=0; i<4097; i++)
{
fputc('a', fp);
}
while(1);
return 0;
}
6.3 关于时间的操作
1> 函数原型
#include
time_t time(time_t *tloc);
功能:获取系统当前时间的毫秒数
参数:如果是NULL,则通过返回值返回毫秒数
如果参数不是NULL,则可以通过参数得到毫秒数
返回值:成功返回毫秒数,失败返回time_t类型的-1,并置位错误码
struct tm *localtime(const time_t *timep);
功能:通过给定的毫秒数,转变成时间
参数:毫秒数
返回值:struct tm结构体指针,失败返回NULL,并置位错误码
struct tm原型:
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) */
int tm_year; /* Year - 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 */
};
#include
#include
#include
#include
int main(int argc, const char *argv[])
{
time_t sys_time = time(NULL); //获取系统时间的毫秒数
//将毫秒数转变成时间结构体
struct tm *fomattime = localtime(&sys_time);
printf("%4d-%2d-%2d %2d:%2d:%2d\n", fomattime->tm_year+1900\
,fomattime->tm_mon+1,\
fomattime->tm_mday,\
fomattime->tm_hour,\
fomattime->tm_min,\
fomattime->tm_sec);
return 0;
}
七、格式化控制相关的函数
7.1 sprintf函数
#include
int sprintf(char *str, const char *format, ...);
功能:向给定的字符数组中,存放进行了格式化后的字符串
参数1:字符数组首地址
参数2:格式串
参数3:格式串对应的可变参数
返回值:成功返回格式串的长度,失败返回负数
注意:当进行格式串时,格式串的长度比字符数组的长度大时,编译时会给出voerflow的警告,运行时会报段错误,保险起见,我们可以使用snprintf
#include
#include
#include
#include
int main(int argc, const char *argv[])
{
char str[50];
time_t sys_time = time(NULL); //获取系统时间的毫秒数
//将毫秒数转变成时间结构体
struct tm *fomattime = localtime(&sys_time);
//使用sprintf将格式串转换为字符串
sprintf(str,"%4d-%2d-%2d %2d:%2d:%2d", fomattime->tm_year+1900\
,fomattime->tm_mon+1,\
fomattime->tm_mday,\
fomattime->tm_hour,\
fomattime->tm_min,\
fomattime->tm_sec);
printf("str = %s\n", str);
return 0;
}
7.2 snprintf函数
int snprintf(char *str, size_t size, const char *format, ...);
功能:将格式串转成字符串,但是有长度size控制,并在后面自动不上'\0'
参数1:存放格式化串的数组
参数2:格式化的长度
参数3:格式控制串
参数4:可变参数
返回值:成功返回格式化的字符格式, 失败返回负数
#include
#include
#include
int main(int argc, const char *argv[])
{
char s[10];
//使用snprintf将格式串转换为字符串
snprintf(s, sizeof(s), "hello world ni hao");
printf("s = %s\n", s);
return 0;
}
7.3 fprintf函数
#include
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
功能:向给定文件中写入一个格式串
参数1:文件指针
参数2:格式化串
参数3:不定参数,根据格式化串中的格式控制符来确定个数
返回:成功返回输出的个数, 失败返回负数
#include
#include
#include
int main(int argc, const char *argv[])
{
int m = 23041;
char name[20] = "班:张鹏鹏";
fprintf(stdout, "%d%s\n", m, name); //向标准输出文件中输出数据
//向文件中输出数据
FILE *fp;
//以只写的形式打开文件
if((fp = fopen("./Test.txt", "w")) == NULL)
{
perror("open file");
return -1;
}
//将格式化串写入文件
fprintf(fp, "%s %s\n", "zhangsan", "123456");
fprintf(fp, "%s %s\n", "lisi", "111111");
//关闭文件
fclose(fp);
return 0;
}
7.3 fscanf函数
#include
int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
功能:从给定文件中,以格式化控制符从文件中摘取数据放入到程序中
参数1:文件指针
参数2:格式控制串
参数3:地址列表
返回值:成功返回读取字符个数,失败返回EOF并置位错误码
#include
#include
#include
int main(int argc, const char *argv[])
{
char userName[20]; //存储账号
char pwd[20]; //存储密码
char loginName[20] = "lisi";
char loginPwd[20] = "111111";
//打开文件读取数据
FILE *fp;
//以只读的形式打开文件
if((fp = fopen("./Test.txt", "r")) == NULL)
{
perror("open file");
return -1;
}
while(1)
{
//从文件中读取数据放入到程序中
int ret = fscanf(fp, "%s%s", userName, pwd);
if(ret == EOF)
{
printf("登录失败\n");
break;
}
//账号和密码匹配
if(strcmp(userName,loginName)==0 && strcmp(pwd, loginPwd)==0)
{
printf("登录成功\n");
break;
}
}
//关闭文件
fclose(fp);
return 0;
}
八、fread、fwrite函数的使用
#include
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能: 从给定文件中,读取nmemb项数据,每项数据大小为size,将数据放入ptr中
参数1:存放数据的指针,是一个万能指针,可以接收任意类型数据
参数2:读取数据每一项的大小
参数3:读取的项数
参数4:文件指针
返回值:成功返回读取的项数,当size为1时,就是成功读取的字节数,失败返回小于项数的值或者0
注意:该函数不能区分是读取失败还是读取到文件结尾,需要使用ferror和feof来区分
size_t fwrite(const void *ptr, size_t size, size_t nmemb,
FILE *stream);
功能:将ptr指向的数据,每项数据的大小为size,一共有nmemb项,写入到stream文件中
参数1:存放数据的指针,是一个万能指针,可以接收任意类型数据
参数2:读取数据每一项的大小
参数3:读取的项数
参数4:文件指针
返回值:成功返回读取的项数,当size为1时,就是成功读取的字节数,失败返回小于项数的值或者0
1> 整形数据的读写
/*******************************写入文件数据****************************/
#include
#include
#include
int main(int argc, const char *argv[])
{
//定义文件指针
FILE *fp;
//以只写的形式打开文件
if((fp = fopen("./Test.txt", "w")) == NULL)
{
perror("open file");
return -1;
}
//使用fwrite将数据写入到文件中
int num = 520;
fwrite(&num, 4, 1, fp);
//关闭文件
fclose(fp);
return 0;
}
/*******************************从文件中读取数据****************************/
#include
#include
#include
int main(int argc, const char *argv[])
{
//定义文件指针
FILE *fp;
//以只写的形式打开文件
if((fp = fopen("./Test.txt", "r")) == NULL)
{
perror("open file");
return -1;
}
//使用fwrite将数据写入到文件中
int num;
fread(&num, 4, 1, fp);
printf("num = %d\n", num);
//关闭文件
fclose(fp);
return 0;
}
2> 字符串的读写
#include
#include
#include
int main(int argc, const char *argv[])
{
char buf[] = "this is a string";
//定义文件指针
FILE *fp;
//以只写的形式打开文件
if((fp = fopen("./Test.txt", "w")) == NULL)
{
perror("open file");
return -1;
}
//将数据写入文件中
fwrite(buf, 1, sizeof(buf), fp);
//关闭文件
fclose(fp);
//读取数据
char str[50];
//以只读的模式打开文件
if((fp = fopen("./Test.txt", "r")) == NULL)
{
perror("open file");
return -1;
}
//从文件中读取数据到str中
fread(str, sizeof(str), 1, fp);
//关闭文件
fclose(fp);
printf("str = %s\n", str);
return 0;
}
3> 结构体的读写
#include
#include
#include
//定义学生结构体类型
typedef struct
{
char name[20]; //姓名
int age; //年龄
double score; //分数
}Stu;
int main(int argc, const char *argv[])
{
Stu s[2] = {{"张三", 18, 99},{"lisi", 30, 100}};
//定义文件指针
FILE *fp;
//以只写的形式打开文件
if((fp = fopen("./Test.txt", "w")) == NULL)
{
perror("open file");
return -1;
}
//将两个数据全部写入文件中去
fwrite(s, sizeof(Stu), 2, fp);
//关闭文件指针
fclose(fp);
//定义变量接收读取的数据
Stu stu;
//打开文件
if((fp = fopen("./Test.txt", "r")) == NULL)
{
perror("open file");
return -1;
}
//从文件中读取一项数据到stu中
fread(&stu, sizeof(Stu), 1, fp);
//关闭文件指针
fclose(fp);
//输出获取的信息
printf("stu.name = %s, age = %d, score = %.2lf\n", stu.name, stu.age, stu.score);
return 0;
}
九、feof、ferror的使用
#include
int feof(FILE *stream);
功能:判断文件是否已经读取到结尾
参数:文件指针
返回值:成功返回非0数字,失败返回0
int ferror(FILE *stream);
功能:判断文件是否读取错误
参数:文件指针
返回值:成功返回非负整数,失败返回0
#include
#include
#include
int main(int argc, const char *argv[])
{
char buf[10] = "";
FILE *fp; //定义文件指针
//以只读的形式打开文件
if((fp= fopen("./Test.txt", "r")) == NULL)
{
perror("open file");
return -1;
}
//循环读取数据
while(1)
{
fread(buf, 1, sizeof(buf), fp);
printf("%s\n", buf);
//判断当前文件是否结束
if(feof(fp))
{
printf("已经读到文件结尾了\n");
break;
}else if(ferror(fp))
{
printf("文件读取失败\n");
break;
}
}
//关闭文件
fclose(fp);
return 0;
}
作业
作业1、获取系统时间,并将系统时间写入文件中,实现现象
1、2023-5-25 14:32:50
2、2023-5-25 14:32:51
3、2023-5-25 14:32:52
//按下ctrl+c,再重新运行程序后
4、2023-5-25 14:33:20
5、2023-5-25 14:33:21
。。。
作业2:使用fread和fwrite完成两个文件的拷贝
1.
#include
#include
int main()
{
// 打开文件
FILE* file = fopen("time.txt", "w+");
if (file == NULL)
{
printf("Failed to open file.\n");
return 1;
}
// 获取系统时间
time_t current_time = time(NULL);
struct tm* local_time = localtime(¤t_time);
// 写入文件
fprintf(file, "%04d-%02d-%02d %02d:%02d:%02d\n",
local_time->tm_year + 1900, local_time->tm_mon + 1, local_time->tm_mday,
local_time->tm_hour, local_time->tm_min, local_time->tm_sec);
fflush(file);
// 关闭文件
fclose(file);
// 延续上次运行的代码
file = fopen("time.txt", "r");
if (file == NULL)
{
printf("Failed to open file.\n");
return 1;
}
time_t last_time;
int year, month, day, hour, minute, second;
if (fscanf(file, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second) == 6)
{
struct tm last_local_time = {0};
last_local_time.tm_year = year - 1900;
last_local_time.tm_mon = month - 1;
last_local_time.tm_mday = day;
last_local_time.tm_hour = hour;
last_local_time.tm_min = minute;
last_local_time.tm_sec = second;
last_time = mktime(&last_local_time);
// 计算时间间隔
time_t elapsed_time = difftime(current_time, last_time);
printf("Elapsed time: %ld seconds.\n", elapsed_time);
}
fclose(file);
return 0;
}
2.
#include
#define BUFFER_SIZE 1024
int main()
{
FILE *src_file = fopen("src_file.txt", "rb");
FILE *dst_file = fopen("dst_file.txt", "wb");
if (src_file == NULL || dst_file == NULL)
{
perror("open file");
return 1;
}
char buffer[BUFFER_SIZE];
size_t bytes_read;
while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, src_file)) > 0)
{
fwrite(buffer, 1, bytes_read, dst_file);
}
fclose(src_file);
fclose(dst_file);
return 0;
}