I/O进程学习——2
一、标准I/O:文件流API补充
fread
函数功能:
按照指定的大小,分块读取文件流的字符。
函数原型:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
函数参数:
参数 | 解释 |
---|---|
ptr | 将读取到的数据写入这个ptr指针的空间中(缓冲区) |
size | 读取的每块数据大小 |
nmemb | 读取的总块数 |
stream | 被读取数据的文件流 |
函数返回值:
状态 | 解释 |
---|---|
成功 | 返回值为 成功读取到的块数 |
失败/到文件结尾 | 返回值为 小于块数的数,也可能为0 |
tips: 判断fread是否读到文件结尾,也可以采用feof() 和 ferror()函数来进行判断。
fwrite
函数功能:
按照块数以及每块大小的指定数量,往文件写入数据
函数原型:
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
函数参数:
参数 | 解释 |
---|---|
ptr | 缓冲区(待写入文件流的数据源) |
size | 每块的大小 |
nmemb | 总块数 |
stream | 指针指向被写入文件 |
函数返回值:
状态 | 解释 |
---|---|
成功 | 成功写入的数据块数 |
失败 | 返回一个小于数据块数的数,也可能为0 |
fseek
函数功能:
从宏定义位置,开始偏移n(偏移量)个值
函数内置宏定义:
宏名 | 解释 |
---|---|
SEEK_SET | 文件开头位置 |
SEEK_CUR | 文件指针的当前位置 |
SEEK_END | 文件结尾位置 |
函数原型:
int fseek(FILE *stream, long offset,int whence);
函数参数:
参数 | 解释 |
---|---|
stream | 需要偏移的文件指针 |
offset | 偏移量(正或负,负往前偏移,正往后) |
whence | 偏移前的位置 |
函数返回值:
状态 | 解释 |
---|---|
成功 | 返回0 |
失败 | 返回1,并设置errno(全局错误号) |
ftell
函数功能:
获取文件指针距离开头位置的距离长度(单位为字节)
函数原型:
long ftell(FILE *stream);
fflash
函数功能:
强制刷新缓冲区
函数原型:
int fflush(FILE *stream);
二、文件I/O
文件描述符
操作系统提供给用户用于标识文件的一个特殊符号,这个符号是一个非负整数(>= 0)
stdin —— 0
stdout —— 1
stderr —— 2
1.系统调用函数
open
函数功能:
打开文件,获取文件描述符
函数头文件:
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>
函数原型:
int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);
函数参数:
参数 | 解释 |
---|---|
pathname | 文件路径 |
flags | 文件权限标识 |
(mode_t) mode | (int 宏定义)创建文件后,文件本身的权限,类似于chmod的用法 |
flags解释:
示例:ORDWR | O_CREAT | OTRUNC
flag | 作用 |
---|---|
O_RDONLY(必要之一) | 只读打开 |
O_WRONLY(必要之一) | 只写打开 |
O_RDWR(必要之一) | 读写打开 |
O_APPEND | 追加权限 |
O_CREAT | 创建权限(不存在则创建) |
O_TRUNC | 截断打开(配合WR或者RDWR) |
mode解释:
权限 | 八进制 |
---|---|
可读、可写、可执行 | 7 |
只读 | 4 |
只写 | 2 |
只可执行 | 1 |
函数返回值:
read
函数功能:
函数头文件:
函数原型:
函数参数:
函数返回值:
write
函数功能:
函数头文件:
函数原型:
函数参数:
函数返回值:
close
函数功能:
关闭文件,回收文件描述符(系统资源)
函数头文件:
#include <unistd.h>
函数原型:
int close(int fd);
函数参数:
fd 文件描述符
函数返回值:
状态 | 解释 |
---|---|
成功 | 返回0 |
失败 | 返回-1,并设置errno |
三、作业
1.文件加密
(1)加减数字
/*===============================================
* 文件名称:encrypt_1.c
* 创 建 者:青木莲华
* 创建日期:2025年08月05日
* 描 述:利用加减值加密文件
================================================*/
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
FILE *fp = fopen("1.txt","r+");
if(fp == NULL)
{
perror("fopen");
return 0;
}
//缓冲区
char buffer[1024] = {0};
int i,len,ret;
while(1)
{
fgets(buffer,sizeof(buffer),fp);
ret = feof(fp);
if(ret != 0)
{
break;
}
len = strlen(buffer);
for(i = 0 ; i < len - 1 ; i++)
{
buffer[i] = (buffer[i] + 13) % 256;
}
fseek(fp,-len,SEEK_CUR);
fputs(buffer,fp);
}
fclose(fp);
return 0;
}
运行截图
(2)高四位和低四位交换
/*===============================================
* 文件名称:encrypt_2.c
* 创 建 者:青木莲华
* 创建日期:2025年08月05日
* 描 述:字符高位低位互换加密
================================================*/
#include <stdio.h>
#include <string.h>
//字符高四位与低四位互换
char exchange(char c)
{
//高位 -> 低位 0000 1111
char high = (c >> 4) & 0x0F;
//低位 -> 高位 1111 0000
char low = (c & 0x0F) << 4;
return high | low;
}
int main(int argc, char *argv[])
{
FILE *fp = fopen("2.txt","r+");
if(fp == NULL)
{
perror("fopen");
return 0;
}
char buffer[1024] = {0};
int i,ret,len = 0;
while(1)
{
memset(buffer,0,sizeof(buffer));
fgets(buffer,sizeof(buffer),fp);
ret = feof(fp);
if(ret != 0)
break;
len = strlen(buffer);
for(i = 0 ; i < len - 1 ; i++) //len - 1 是为了不加密换行符
buffer[i] = exchange(buffer[i]);
fseek(fp,-len,SEEK_CUR); //偏移量为上一行字符长度 负数往前偏移
fputs(buffer,fp);
}
fclose(fp);
return 0;
}
运行截图
(3)按照密钥加密
/*===============================================
* 文件名称:encrypt_3.c
* 创 建 者:青木莲华
* 创建日期:2025年08月05日
* 描 述:模拟密钥加密文件
================================================*/
#include <stdio.h>
#include <string.h>
//模拟密钥
const char key[8] = {'A','1','O','5','K','9','I','g'};
void encrypt(char *s,int len,int mode)
{
int i;
if(mode == 1)
for(i = 0 ; i < len ; i++) //加密
s[i] = s[i] + key[i % 8];
else if(mode == 2)
for(i = 0 ; i < len ; i++)
s[i] = s[i] - key[i % 8]; //反向加密(解密)
}
int main(int argc, char *argv[])
{
FILE *fp = fopen("3.txt","r+");
if(fp == NULL)
{
perror("f_open");
return 0;
}
char buffer[1024] = {0};
int len,ret,mode = 0;
printf("请选择模式: 1.加密 2.反加密\n");
scanf("%d",&mode);
if(mode < 1 || mode > 2)
{
printf("The mode error!\n");
return 0;
}
while(1)
{
memset(buffer,0,sizeof(buffer));
fgets(buffer,sizeof(buffer),fp);
ret = feof(fp);
if(ret != 0)
break;
len = strlen(buffer);
encrypt(buffer,len - 1,mode);
fseek(fp,-len,SEEK_CUR);
fputs(buffer,fp);
}
fclose(fp);
return 0;
}
运行截图
2.完成图像操作
(1)自行制作图像
/*===============================================
* 文件名称:color.c
* 创 建 者:青木莲华
* 创建日期:2025年08月05日
* 描 述:fwrite练习
================================================*/
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *fp = fopen("1.ppm","w");
if(fp == NULL)
return -1;
char head[] = "P6\n1024 1024\n255\n";
fwrite(head,sizeof(head)-1,1,fp);
char color[3] = {255,255,255};
int i,j;
for(i = 0 ; i < 1024 ; i++)
{
for(j = 0 ; j < 1024 ; j++)
{
color[0] = j % 255;
color[1] = j % 255;
color[2] = j % 255;
fwrite(color,3,1,fp);
}
}
fclose(fp);
return 0;
}
运行截图
(2)图像的反差处理
/*===============================================
* 文件名称:color_bmp.c
* 创 建 者:青木莲华
* 创建日期:2025年08月05日
* 描 述:利用fwrite和fread进行bmp图像处理
================================================*/
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp_read = fopen("1.bmp","r");
if(fp_read == NULL)
return 0;
FILE *fp_write = fopen("1_out.bmp","w");
if(fp_write == NULL)
return 0;
//处理bmp文件头
char head[54] = {0};
fread(head,54,1,fp_read);
fwrite(head,54,1,fp_write);
//处理bmp文件长度和宽度
int w = *(int *)&head[18];
int h = *(int *)&head[22];
printf("w = %d , h = %d\n",w,h);
//读取bmp像素块
char rgb[w * h][3];
fread(rgb,w * h,3,fp_read);
//负色处理
int i;
for(i = 0 ; i < w * h ; i++)
{
rgb[i][0] = 255 - rgb[i][0];
rgb[i][1] = 255 - rgb[i][1];
rgb[i][2] = 255 - rgb[i][2];
}
fwrite(rgb,w*h,3,fp_write);
fclose(fp_read);
fclose(fp_write);
return 0;
}
运行截图
(3)图像打码
/*===============================================
* 文件名称:mosaic.c
* 创 建 者:青木莲华
* 创建日期:2025年08月05日
* 描 述:利用标准IO对图像进行打码处理
================================================*/
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp_read = fopen("1.bmp","r");
if(fp_read == NULL)
{
perror("fp_read");
return 0;
}
FILE *fp_out = fopen("1_mosaic.bmp","w");
if(fp_out == NULL)
{
perror("fp_out");
return 0;
}
//处理bmp文件头
char head[54] = {0};
fread(head,54,1,fp_read);
fwrite(head,54,1,fp_out);
//处理bmp文件长度和宽度
int w = *(int *)&head[18];
int h = *(int *)&head[22];
printf("图片宽:%d , 高:%d\n",w,h);
//读取bmp像素块
char buffer[h][w][3];
fread(buffer,w * h,3,fp_read);
//固定像素坐标轴
int block_x = 100,block_y = 100;
//填充坐标轴
int x = 0,y = 0;
//每个马赛克块的边长
int msize = 25;
//每行每列的马赛克块数
int mcount = 16;
//每个马赛克块的像素填充颜色
char rgb[3] = {0};
//对数据进行打码处理
for(int i = 0 ; i < mcount ; i++)
{
for(int j = 0 ; j < mcount ; j++)
{
//计算行坐标
x = block_x + j * msize;
//计算列坐标
y = block_y + i * msize;
//给填充颜色赋值
rgb[0] = buffer[y][x][0];
rgb[1] = buffer[y][x][1];
rgb[2] = buffer[y][x][2];
for(int l = 0 ; l < msize ; l++)
{
for(int r = 0 ; r < msize ; r++)
{
buffer[y+l][x+r][0] = rgb[0];
buffer[y+l][x+r][1] = rgb[1];
buffer[y+l][x+r][2] = rgb[2];
}
}
}
}
fwrite(buffer,3,w*h,fp_out);
printf("图像处理完毕。\n");
fclose(fp_read);
fclose(fp_out);
return 0;
}
运行截图