Linux学习-应用软件编程(fread/fwrite,流定义相关接口)

fread

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

功能

按块从文件读取数据,从文件中读 nmemb 个、每个 size 字节的元素,存入 ptr 指向的内存。

参数
  • ptr :存储读取数据的内存首地址(需提前分配足够空间,如定义数组、用 malloc 申请堆内存 )。

  • size :单个元素的字节数(同 fwrite ,需和写入时的 size 一致,否则数据会错位 )。

  • nmemb :希望读取的元素个数(尝试读 size * nmemb 字节,实际读多少看文件内容 )。

  • stream :文件流指针(通过 fopen 打开,需以可读模式如 "r+" 等打开 )。

返回值
  • 成功:返回实际读到的元素个数(等于 nmemb 表示读满;若文件末尾不够 nmemb 个元素,返回实际读到的数量 )。

  • 文件末尾:返回 0 (可用来判断是否读完文件 )。

    #include<stdio.h>
    struct stu
    {
    int id;
    char name[100];
    int score;
    };
    int main(int argc,const charargv[])
    {
    FILE
    fp = fopen("./1.txt","r");
    if(NULL == fp)
    {
    printf("fopen error\n");
    return -1;
    }
    struct stu s;
    struct stu ss[10];
    size_t cnt = fread(&s,sizeof(struct stu),1,fp);

    复制代码
      printf("cnt = %ld\n",cnt);
      printf("%d %s %d\n",s.id,s.name,s.score);
    
      cnt = fread(ss,sizeof(struct stu),10,fp);
      printf("cnt = %ld\n",cnt);
    
      for(int i = 0;i < cnt;i++)
      {
          printf("%d %s %d\n",ss[i].id,ss[i].name,ss[i].score);
      }
      fclose(fp);

    }

fwrite

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

功能

按块向文件写入数据,把 ptr 指向的内存数据,以「 size 字节/元素 、共 nmemb 个元素」的形式写入文件。

参数
  • ptr :要写入数据的内存首地址(常搭配数组、结构体等,传递 &变量 或数组名)。

  • size :单个元素的字节数(如 sizeof(int) 表示 int 类型占 4 字节)。

  • nmemb :要写入的元素个数(需和 size 匹配,总写入字节 = size * nmemb )。

  • stream :文件流指针(通过 fopen 打开文件获得,需确保以可写模式如 "wb" 、 "a+" 等打开 )。

返回值
  • 成功:返回实际写入的元素个数(正常应等于 nmemb ;若磁盘满、权限不足等,可能小于)。

    #include<stdio.h>

    struct stu
    {
    int id;
    char name[100];
    int score;
    };
    int main(int argc,const charargv[])
    {
    FILE
    fp = fopen("./1.txt","w");
    if(NULL == fp)
    {
    printf("fopen error\n");
    return -1;
    }
    struct stu ss[5] = {{1,"zahngsan",99},{2,"lisi",90},{3,"wangwu",98},{4,"maliu",67},{5,"wanger",100}};
    size_t cnt = fwrite(ss,sizeof(struct stu),5,fp);
    printf("cnt = %ld\n",cnt);
    fclose(fp);
    }

bmp

复制代码
#pragma pack(1)

//bmp文件相关信息
typedef struct tagBITMAPFILEHEADER {
    short    bfType;         // 文件类型标志
    int      bfSize;         // 文件大小,单位为字节
    short    bfReserved1;    // 保留字节
    short    bfReserved2;    // 保留字节
    int      bfOffBits;      // 数据偏移量,即实际图像数据开始的位置
}Bmp_file_head_t;
//bmp图像信息
typedef struct tagBITMAPINFOHEADER {
    int   biSize;         // BITMAPINFOHEADER的大小,单位为字节
    int    biWidth;        // 位图的宽度,单位为像素
    int    biHeight;       // 位图的高度,单位为像素
    short    biPlanes;       // 目标设备的位平面数,必须为1
    short    biBitCount;     // 每像素位数(颜色深度)
    int   biCompression;  // 图像压缩类型
    int   biSizeImage;    // 图像大小,单位为字节
    int    biXPelsPerMeter;// 水平分辨率,单位为像素/米
    int    biYPelsPerMeter;// 垂直分辨率,单位为像素/米
    int   biClrUsed;      // 实际使用颜色数
    int   biClrImportant; // 重要颜色数
}Bmp_info_t;
#pragma pack()

int get_bmp_head_info(const char *bmpname, Bmp_file_head_t *pheadinfo, Bmp_info_t *pbmpinfo)
{
	FILE *fp = fopen(bmpname, "r");
	if (NULL == fp)
	{
		printf("fopen error\n");
		return -1;
	}


	fread(pheadinfo, sizeof(Bmp_file_head_t), 1, fp);
	fread(pbmpinfo, sizeof(Bmp_info_t), 1, fp);


	fclose(fp);

	return 0;
}

int main(int argc, const char *argv[])
{

	Bmp_file_head_t headinfo;
	Bmp_info_t bmpinfo;

	get_bmp_head_info("./3.bmp", &headinfo, &bmpinfo);

	printf("sizeof(Bmp_file_head_t) = %ld\n", sizeof(Bmp_file_head_t));
	printf("sizeof(Bmp_info_t) = %ld\n", sizeof(Bmp_info_t));
	printf("biWidth = %d, biHeight = %d, biBitCount = %d\n", bmpinfo.biWidth, bmpinfo.biHeight, bmpinfo.biBitCount);

	return 0;
}

流定位相关接口

fseek

int fseek(FILE *stream, long offset, int whence);

功能

实现文件流的重新定位,用于调整文件内部指针的位置,决定后续读写操作从文件的哪个位置开始。

参数
  • stream :需要进行定位操作的文件流指针,由 fopen 等函数打开文件后获得。

  • offset :偏移量,用于指定相对于 whence 位置移动的字节数,可正(向后移动 )、可负(向前移动 ,但需注意不能越界 )。

  • whence :定位的相对基准位置,有以下宏定义可选:

  • SEEK_SET :以文件开头为基准进行偏移, offset 为相对于文件开头的偏移字节数。

  • SEEK_CUR :以文件当前读写位置为基准进行偏移, offset 是相对于当前位置的偏移量。

  • SEEK_END :以文件末尾为基准进行偏移, offset 常搭配负数,实现从末尾往前定位(如 fseek(stream, -10, SEEK_END) 表示定位到文件末尾向前 10 字节处 )。

返回值
  • 成功:返回 当前偏移量。

  • 失败:返回 -1 ,常见失败情况如偏移量导致越界(如 SEEK_SET 时 offset 为负数 )、文件流异常等。

rewind(fp) ==>fseek(fp,0,SEEK_SET)

ftell

long ftell(FILE *stream);

功能

获取文件流当前位置到文件开头的偏移量,即返回当前文件指针距离文件起始位置的字节数,可用于判断文件大小、辅助 fseek 定位等场景。

返回值

偏移量:byte

练习

复制代码
#include<stdio.h>
#include<stdlib.h>
struct stu
{
    int id;
    char name[100];
    int score;
};
int main(int argc,const char*argv[])
{
    FILE*fp = fopen("./1.txt","w+");
    if(NULL == fp)
    {
        printf("fopen error\n");
        return -1;
    }
    struct stu ss[5] = {{1,"zahngsan",99},{2,"lisi",90},{3,"wangwu",98},{4,"maliu",67},{5,"wanger",100}};
    fwrite(ss,sizeof(struct stu),5,fp);

    fseek(fp,0,SEEK_END);
    long len = ftell(fp);
    rewind(fp);

    FILE*fp1 = fopen("./2.txt","w");
    if(NULL == fp1)
    {
        printf("fopen error\n");
        return -1;
    }
    //空洞文件
    fseek(fp1,len - 1,SEEK_SET);
    int ret = fputc('\0',fp1);
    if(EOF == ret)
    {
        printf("磁盘空间不足\n");
        return -1;
    }

    fseek(fp1,0,SEEK_SET);
    char *buff = malloc(len);

    fread(buff,1,len,fp);
    fwrite(buff,1,len,fp1);

    free(buff);
    fclose(fp);
    fclose(fp1);
}

strtok

char *strtok(char *str, const char *delim);

功能

按分隔符截取字符串,从 str 中逐个提取由 delim 分隔的子串。首次调用需传入待分割的完整字符串 str ,后续调用传入 NULL 即可继续分割剩余部分(内部会维护静态指针记录位置 )。

参数
  • str :

  • 首次调用:传入待分割的原始字符串(会被函数修改,分割后原字符串会被分隔符替换为 \0 ,用于标记子串结束 )。

  • 后续调用:传入 NULL ,函数会基于内部静态指针,继续分割剩余未处理的部分。

  • delim :

传入分隔符字符串(如 ",-" 表示逗号、减号都可作为分隔符 ),只要遇到 delim 中任意字符,就会停止当前子串截取。

返回值
  • 成功:返回当前截取到的子串首地址(如分割 "a,b,c" ,首次返回 "a" 的地址,后续依次返回 "b" 、 "c" )。

  • 失败/结束:返回 NULL (当没有可分割的子串时触发 )。

练习

实现一个单词查询软件: 用户从终端输入一个单词,查找该单词的意思并打印; 若用户输入".quit",则退出该软件。

复制代码
#include<stdio.h>
#include <string.h>
int main(int argc,const char*argv[])
{
    FILE*fp = fopen("./dict.txt","r");
    if(NULL == fp)
    {
        printf("fopen error\n");
        return -1;
    }
    rewind(fp);
    char s[1024];
    printf("输入单词\n");
    scanf("%s",s);
    char buff[1024] = {0};
    if(0 == strcmp(".quit",s))
    {
        return 0;    
    }
    
    
     char *p = fgets(buff,sizeof(buff),fp);

    while(p != NULL)
    {
        char *b = strtok(buff," ");
        if(0 == strcmp(b,s))
        {
            b = strtok(NULL,"\r");
            printf("%s%s\n",s,b);
            break;
        }
    p = fgets(buff,sizeof(buff),fp);
    }
    if(p == NULL)
    {
        printf("not find\n");
        return 0;
    }
    fclose(fp);

}
相关推荐
为什么名字不能重复呢?14 分钟前
AJAX入门(1)
学习·ajax
晨非辰24 分钟前
#C语言——刷题攻略:牛客编程入门训练(八):分支控制(二)
c语言·开发语言·经验分享·学习·其他·学习方法·visual studio
三次拒绝王俊凯1 小时前
删除Microsoft Edge中的在线填充数据
学习
楼田莉子2 小时前
(3万字详解)Linux系统学习:深入了解Linux系统开发工具
linux·服务器·笔记·git·学习·vim
思扬092810 小时前
前端学习日记 - 前端函数防抖详解
前端·学习
小郝 小郝13 小时前
开启单片机
c语言·单片机·嵌入式硬件·学习·51单片机
小杜的生信筆記14 小时前
基于R语言,“上百种机器学习模型”学习教程 | Mime包
开发语言·学习·机器学习·r语言·sci
慕y27414 小时前
Java学习第一百二十二部分——HTTPS
网络协议·学习·https
醉卧红尘的鱼19 小时前
随机向量正交投影定理(Orthogonal Projection Theorem, OPT)_学习笔记
学习·算法