002库函数IO基础二
fopen补充

其中还有二进制模式的
在原有mode字符串后加b,例如:
"rb":二进制只读(文件必须存在)"rb+":二进制读写(文件必须存在)"wb":二进制只写(文件不存在则创建,存在则清空)"wb+":二进制读写(文件不存在则创建,存在则清空)"ab":二进制追加只写(文件不存在则创建,写数据到末尾)"ab+":二进制追加读写(文件不存在则创建,写数据到末尾)
文本和二进制的区别
-
文本模式下,写入和读取的数据可能与实际存储的数据不同。
Windows 下文本模式会转换换行符(
\n→\r\n),二进制模式不转换 -
二进制模式下,写入和读取的数据与实际存储的数据一致,适用于处理图片、音频等二进制文件
所有字符(包括特殊字符)都会被当作普通字节直接读写,保持原始存储形式。
一、文件写入方式
标准 IO 提供三种核心文件写入方式:
-
字符写入:按单个字符维度写入文件;


过程:输出--->写缓冲区--->内核写缓冲区--->文件内
-
按行写入:按整行维度写入文件;


以\0为终止符,遇到\0立即停止写入,且不写入\0本身 -
按块写入:按指定大小的块维度写入文件。


写出错时,文件光标位置结果值不确定
二、文件位置
每个被打开文件的结构体中都有一个位置指示器(简单理解:位置指示器是文件光标)
注意:被打开的文件的光标默认是在文件开头的。
- 设置位移


- 获取位移


可以用来求文件的数据大小
确保文件的光标在末尾
调用fseek设置SEEK_END 用追加的方式也是在末尾
使用ftell计算光标的偏移量
得到文本数据大小
练习:要求利用标准IO函数接口实现计算一个本地磁盘某个文件的大小,要求文件名称通过命令行进行传递,并进行验证是否正确( ls -l)。
#include <stdio.h>
#include <stdlib.h>
int main(int argc,const char *argv[])
{
//1、要求计算大小的
// 文件的路径需要通过命令行参数传递进来
if(2 != argc){
printf("Usage:%s filepath\n",argv[0]);
exit(1);
}
//2、打开文件
FILE *fp = fopen(argv[1],"rb");
if(fp == NULL){
perror("fopen");
exit(1);
}
//3、循环读取文件内容
int i = 0;
while(fgetc(fp) != EOF){
i++;
}
printf("文件共有 %d 个字符\n",i);
//4、关闭文件
fclose(fp);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main(int argc,const char *argv[])
{
//1、要求计算大小的
// 文件的路径需要通过命令行参数传递进来
if(2 != argc){
printf("Usage:%s filepath\n",argv[0]);
exit(1);
}
//2、打开文件
FILE *fp = fopen(argv[1],"ab"); //a追加模式,光标会在文本末尾
if(fp == NULL){
perror("fopen");
exit(1);
}
// //3、循环读取文件内容
// int i = 0;
// while(fgetc(fp) != EOF){
// i++;
// }
printf("文件共有 %d 个字符\n",ftell(fp));
//4、关闭文件
fclose(fp);
return 0;
}
练习:利用标准IO函数接口实现文件拷贝,把本地磁盘的文件A中的数据完整的拷贝到另一个文本B中,如果文本B不存在则创建,要求文本A的名称和文本B的名称通过命令行传递,并进行验证是否正确。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFERSIZE 512
int main(int argc,const char *argv[])
{
int sizeA=0; //文件A的大小
int loop_cnt=0; //循环次数
int remainder = 0; //余数
//1、文件的路径需要通过命令行参数传递进来
if(3!=argc){
printf("Usage:%s filepath\n",argv[0]);
exit(1);
}
//2、打开文件A、B
FILE *A = fopen(argv[1],"rb");
if(NULL == A){
perror("fopen:A");
exit(1);
}
FILE *B = fopen(argv[2],"wb");
if(NULL == B){
perror("fopen:B");
exit(1);
}
//3、读取A中的内容
//为了提高程序运行效率,采用空间换时间,定义数据缓冲区来存储
char data_buffer[BUFFERSIZE] ={0};
fseek(A,0,SEEK_END); //将光标偏移到文件末尾
sizeA = ftell(A);
fseek(A, 0, SEEK_SET); //将光标偏移到文件开头
//计算读取数据块的次数,循环写入
loop_cnt= sizeA / BUFFERSIZE;
remainder = sizeA % BUFFERSIZE;
while (loop_cnt--) {
//读取数据到缓冲区
fread(data_buffer, BUFFERSIZE,1, A);
//将缓冲区数据写入文件B
fwrite(data_buffer, BUFFERSIZE,1, B);
}
//处理剩余数据
if (remainder > 0) {
//清空缓冲区
memset(data_buffer, 0, BUFFERSIZE);
//读取剩余数据到缓冲区
fread(data_buffer, remainder, 1, A);
//将缓冲区数据写入文件B
fwrite(data_buffer, remainder, 1, B);
}
//验证文件B的大小是否和文件A一致
int sizeB = ftell(B);
printf("文件A的大小为:%ld 字节\n", sizeA);
printf("文件B的大小为:%ld 字节\n", sizeB);
if(sizeA == sizeB){
printf("文件复制成功!\n");
}else{
printf("文件复制失败!\n");
}
//4、关闭文件
fclose(A);
fclose(B);
return 0;
}
三、 格式访问
标准库中除了以上关于文件读写的函数之外,还提供了一些可以对文件进行格式化读写的函数接口,在C99标准中有关于这些函数的描述,如下:

注意:一般常用的关于文件IO的格式化函数有printf、fprintf、scanf、fscanf、sprintf、snprintf。


作业:设计程序,获取当前系统时间,把时间转换为特定格式”yy年mm月dd日 星期x tt:mm:ss”,并每隔1s写入到本地磁盘中一个叫做log.txt的文本中,如果文本不存在则创建。
获取时间的函数


/*
* © 2026 guokun. All rights reserved.
* email:guokun603@gmail.com
* 获取当前系统时间
*/
#include <stdio.h>
#include <time.h>
// 星期转换数组
const char* week_day[] = {"日", "一", "二", "三", "四", "五", "六"};
int main (int argc , const char * argv[])
{
time_t now;
while (1)
{
//1、获取当前系统时间
time(&now);
if (-1 == now) {
perror("time");
return -1;
}
//2、转换为本地时间
struct tm *local = localtime(&now);
if (NULL == local) {
perror("localtime");
return -1;
}
//打开文件
FILE *fp = fopen("log.txt","ab");
if(NULL == fp){
perror("fopen");
return -1;
}
//将时间写入文件
fprintf(fp,"当前系统时间为:""%04d年%02d月%02d日 星期%s %02d:%02d:%02d\n",
local->tm_year + 1900,
local->tm_mon + 1,
local->tm_mday,
week_day[local->tm_wday],
local->tm_hour,
local->tm_min,
local->tm_sec);
//关闭文件
fclose(fp);
sleep(1);
}
return 0;
}

浙公网安备 33010602011771号