前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >文件I/O (二).结构体存取(1)

文件I/O (二).结构体存取(1)

作者头像
franket
发布2021-09-16 09:48:28
3320
发布2021-09-16 09:48:28
举报
文章被收录于专栏:技术杂记技术杂记

前言

当前的计算系统除了包括对数据有 加工和处理 以外还有 搬运

这个 搬运 代表着 输入和输出 ,及 input/output ,简称 I/O

UNIX/Linux 的缔造者们将数据的 来源和目标 都抽象为 文件,所以在 UNIX/Linux 系统中 一切皆文件

一切皆文件 不仅仅对磁盘,还包括鼠标,键盘,显示器这些设备,那么对这些设备的操作也都抽象成了对 文件的I/O操作

关于 标准I/O 可以参看之前的文章 《标准I/O (一)》 ,类Unix系统中除了 标准I/O 还有 文件I/O,可以完成相同工作,关于 文件I/O 还有它们之间的区别可以参看之前的文章 《文件I/O (一)》,关于C语言的API(linux)可以参看 Linux C API 参考手册 在线文档

这里分享一下我在学习 文件 I/O 库过程中的笔记和心得


概要


文件IO库的常用函数

下面是一些 文件IO库 中的常用函数

代码语言:javascript
复制
int open( const char *pathname, int flags)
int open( const char *pathname, int flags, mode_t mode)
ssize_t read(int fd, void *buf, size_t count)
ssize_t write(int fd, const void *buf, size_t count)
off_t lseek(int fildes, off_t offset, int whence)
int close(int fd)

代码示例

要求

结构体定义

代码语言:javascript
复制
struct stu
{
  int id;
  char name[5];
  int score;
};
  • 1)手工输入5个学生信息,并将结果存入文件f1中
  • 2)找出f1中学生分数最高的那个人(有可能多个并列第一),将这个人的信息写入文件f2.

要求:用非缓冲IO实现

代码示例

代码语言:javascript
复制
#include <stdio.h> 
#include <unistd.h> //文件IO函数包含其中,缺少这个头文件read,write,close 会报错
#include <fcntl.h> //open函数包含其中,还有一些重要的宏定义

typedef struct student  //student 结构体定义
{
  int id;
  char name[5];
  int score;
}ST;

int main()
{
  int res=-1,fa=0,fb=0,maxscore=0,tscore=0,i=0;
  char *fileA="f1";
  char *fileB="f2"; //变量定义与初始化
  ST stutmp,stu[5]={
    {11,"xiao",18},
    {13,"hong",88},
    {16,"tuna",98},
    {19,"tony",60},
    {90,"duno",98}
  }; 
  
  if (-1==(fa=open(fileA,O_RDWR|O_CREAT|O_TRUNC,0644))) //以读写方式打开文件A
  {
    printf("cannot open file:%s\n",fileA);
    return res;
  }
  if (-1==(fb=open(fileB,O_RDWR|O_CREAT|O_TRUNC,0644))) //以读写方式打开文件B
  {
    printf("cannot open file:%s\n",fileB);
    return res;
  }
  if(sizeof(ST)*5 != write(fa,stu,sizeof(ST)*5)) //将结构体数组所有内容写到文件A ,顺利的情况下会返回实际写入的字节数,利用这个特性来判断有没写成功
  {
    printf("write error on:%s\n",fileA);
    return res;
  }

  lseek(fa,sizeof(ST)-sizeof(int),SEEK_SET); //将文件指针定位到分数的部分,SEEK_SET 代表的是0,这个宏是在fcntl.h中定义的,意思是偏移量相对位置为文件的开头
  if(sizeof(int)!=read(fa,&maxscore,sizeof(int))) //将分数读到maxscore中,作为初始的最大分数
  {
    printf("read error on:%s\n",fileA);
    return res;
  }
  lseek(fa,sizeof(ST)-sizeof(int),SEEK_SET); //重新将文件指针定位到分数的部分
  for(i=0;i<5;i++)
  {
    if(sizeof(int) != read(fa,&tscore,sizeof(int))) //将分数写到tscore中
    {
      printf("read error on:%s\n",fileA);
      return res;
    }
    if(maxscore < tscore) maxscore=tscore; //将分数与初始的maxscore进行比较,如果当前分数较大,则替换掉maxscore中的值
    lseek(fa,sizeof(ST)-sizeof(int),SEEK_CUR); //从当前位置开始,定位到下一个分数处,SEEK_CUR代表的是1,这个宏是在fcntl.h中定义的,意思是偏移量相对位置为当前位置
  }

  lseek(fa,sizeof(ST)-sizeof(int),SEEK_SET); //重新将文件指针定位到第一个分数的位置
  for(tscore=0,i=0;i<5;i++)
  {
    if(sizeof(int) != read(fa,&tscore,sizeof(int))) //将分数写到tscore中
    {
      printf("read error on:%s\n",fileA);
      return res;
    }
    if(maxscore == tscore) //如果tscore与maxscore相等,就读取这个结构体的内容,并将这个结构体的内容写到文件B中
    {
      lseek(fa,-1*sizeof(ST),SEEK_CUR); //从当前位置后退一个结构体的长度,注意 -1*与SEEK_CUR的用法
      if (sizeof(ST) != read(fa,&stutmp,sizeof(ST))) //读取这个结构体的内容到stutmp中
      {
	printf("read error on:%s\n",fileA); 
	return res;
      }
      if(-1 == write(fb,&stutmp,sizeof(ST))) //将stutmp中的内容写到文件B中
      {
	printf("write error on:%s\n",fileB); 
	return res;
      }
    }  
    lseek(fa,sizeof(ST)-sizeof(int),SEEK_CUR); //定位到下一个分数的部分
  }

  close(fa);
  close(fb);
  res=0;
  return res;
}

Note: 文件打开数是一种系统资源,是有上限的,虽然程序退出后,系统会帮忙清理,但在程序设计中,打开文件,使用完后进行手动关闭是一种很好的习惯,这样可以有效避免缓存未刷新的潜在隐患,也可以更加节约资源

编译执行

代码语言:javascript
复制
emacs@ubuntu:~/c$ ll f1
ls: 无法访问f1: 没有那个文件或目录
emacs@ubuntu:~/c$ ll f2
ls: 无法访问f2: 没有那个文件或目录
emacs@ubuntu:~/c$ alias gtc
alias gtc='gcc -Wall -g -o'
emacs@ubuntu:~/c$ gtc savetofile.x savetofile.c
emacs@ubuntu:~/c$ ./savetofile.x 
emacs@ubuntu:~/c$ ll f1
-rw-r--r-- 1 emacs emacs 80 2016-12-30 04:08 f1
emacs@ubuntu:~/c$ ll f2
-rw-r--r-- 1 emacs emacs 32 2016-12-30 04:08 f2
emacs@ubuntu:~/c$ xxd f1
0000000: 0b00 0000 7869 616f 0000 0000 1200 0000  ....xiao........
0000010: 0d00 0000 686f 6e67 0000 0000 5800 0000  ....hong....X...
0000020: 1000 0000 7475 6e61 0000 0000 6200 0000  ....tuna....b...
0000030: 1300 0000 746f 6e79 0000 0000 3c00 0000  ....tony....<...
0000040: 5a00 0000 6475 6e6f 0000 0000 6200 0000  Z...duno....b...
emacs@ubuntu:~/c$ xxd f2
0000000: 1000 0000 7475 6e61 0000 0000 6200 0000  ....tuna....b...
0000010: 5a00 0000 6475 6e6f 0000 0000 6200 0000  Z...duno....b...
emacs@ubuntu:~/c$ 

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 概要
    • 文件IO库的常用函数
      • 代码示例
        • 要求
        • 代码示例
        • 编译执行
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档