一、实验目的:

练习用UNIX I/O进行文件读写的编程方法,用UNIX I/O函数管理文本信息、二进制数据、结构体数据,掌握UNIX I/O的基本编程方法。练习测时函数使用,通过测量UNIX I/O函数运行时间,建立UNIX I/O API函数基本开销的概念。

二、实验内容与要求:

先创建用户家目录下创建文件名为“姓名+学号+04”的子目录,作为本次实验目录,本次实验的所有代码都放到该目录下,要求将所有源代码与数据文件打包成文件”学号-姓名-lab4.tar.gz”, 压缩包与实验报告分别上传到指定目录下。

任务1. 在当前用户目录下创建数据文件student.txt,文件的内部信息存储格式为Sname:S#:Sdept:Sage:Ssex,即“姓名:学号:学院:年龄:性别”,每行一条记录,输入不少于10条学生记录,其中包括学生本人记录。调用标准I/O库编写程序task41.c,从文件中查找Sdept字段值为“计算机与网络安全学院”的文本行,输出到文件csStudent.txt中,保存时各字段顺序调整为S#:Sname:Sage: Ssex:Sdept。
提示:从终端读入一个文本行到字符串 char buf[MAXSIZE]可调用函数可调用函数:
“fgets(buf, MAXSIZE, stdin);”,其中stdin是表示键盘输入设备的文件指针。

代码:

#include<stdio.h>
#include<string.h>
#define MAXSIZE 200
int main()
{FILE* fp1, * fp2;char buf[MAXSIZE];char check[] = "计算机与网络安全学院";if ((fp1 = fopen("student.txt", "r")) == NULL){printf(" Open Failed!");return 0;}if ((fp2 = fopen("csStudent.txt", "a+")) == NULL){printf(" Open Failed!");return 0;}while (!feof(fp1))//文本结束时退出循环{fgets(buf, MAXSIZE, fp1);//一行行读入if (strstr(buf, check))//判断是否属于“计算机与网络安全学院”{char* a[6];char buffer[100];a[0] = strtok(buf, ":");//切割字符串成五部分a[1] = strtok(NULL, ":");a[2] = strtok(NULL, ":");a[3] = strtok(NULL, ":");a[4] = strtok(NULL, ":");a[4][3] = 0;//将换行符去掉sprintf(buffer, "%s:%s:%s:%s:%s\n", a[1], a[0], a[3], a[4], a[2]);//格式化写入bufferfputs(buffer, fp2);//将buffer写入文本csStudent}}fclose(fp1);fclose(fp2);return 0;
}

任务2. 调用Unix I/O库函数,编写程序task42.c,从键盘读入5个学生的成绩信息,包括学号、姓名、语文、数学、英语,成绩允许有一位小数,存入一个结构体数组,结构体定义为:

typedef struct _subject {char sno[20];      //学号char name[20];   //姓名float chinese;     //语文成绩float math;        //数学成绩float english;       //英语成绩
}  subject;

代码:

#include<stdio.h>
#include"wrapper.h"
typedef struct _subject {char sno[20];     //学号char name[20];    //姓名float chinese;    //语文成绩float math;      //数学成绩float english;     //英语成绩
}  subject;void main() {int fd = open("task42.txt", O_RDWR | O_CREAT | O_APPEND, 0777);subject student[5];subject stu[3];int i;for (i = 0; i < 5; i++) {scanf("%s%s%f%f%f", student[i].sno, student[i].name, &student[i].chinese, &student[i].math, &student[i].english);write(fd, &student[i], sizeof(student[i]));}lseek(fd, 0, SEEK_SET);read(fd, &stu[0], sizeof(subject));lseek(fd, sizeof(subject), SEEK_CUR);read(fd, &stu[1], sizeof(subject));lseek(fd, sizeof(subject), SEEK_CUR);read(fd, &stu[2], sizeof(subject));for (i = 0; i < 3; i++) {printf("%s %s %.1f %.1f %.1f\n", stu[i].sno, stu[i].name, stu[i].chinese, stu[i].math, stu[i].english);}}

任务3(可选):在Linux环境下,可以调用库函数gettimeofday测量一个代码段的执行时间,请写一个程序task43.c,测量read、write、fread、fwrite函数调用所需的执行时间,并与prof/gprof工具测的结果进行对比,看是否基本一致。并对四个函数的运行时间进行对比分析。
提示:由于一次函数调用时间太短,测量误差太多,应测量上述函数多次(如10000次)运行的时间,结果才会准确。

代码:

#include<stdio.h>
#include"wrapper.h"
//struct  timeval{//       long  tv_sec;  /*秒*///       long  tv_usec; /*微秒*///};
int main() {struct timeval begin, end;double write_time , fwrite_time , read_time , fread_time;int i;char buf[100]="you are good!";int fd = open("test.txt",O_RDWR|O_CREAT|O_APPEND,0777);gettimeofday(&begin,NULL);//10000次writefor(i =0;i<10000;i++){write(fd,buf,1);}gettimeofday(&end,NULL);write_time = end.tv_usec-begin.tv_usec;printf("10000次write的write_time =%.1lf微秒\n",write_time);lseek(fd,0,SEEK_SET);gettimeofday(&begin,NULL);//10000次readfor(i =0;i<10000;i++){read(fd,buf,1);}gettimeofday(&end,NULL);read_time = end.tv_usec-begin.tv_usec;printf("10000次read的read_time =%.1lf微秒\n",read_time);close(fd);FILE* fp1 = fopen("test.txt","w+");gettimeofday(&begin,NULL);//10000次fwritefor(i =0;i<10000;i++){fwrite(buf,1,1,fp1);}gettimeofday(&end,NULL);fwrite_time = end.tv_usec-begin.tv_usec;printf("10000次fwrite的fwrite_time =%.2lf微秒\n",fwrite_time);fclose(fp1);FILE* fp2 = fopen("test.txt","r+");gettimeofday(&begin,NULL);//10000次freadfor(i =0;i<10000;i++){fread(buf,1,1,fp2);}gettimeofday(&end,NULL);fread_time = end.tv_usec-begin.tv_usec;printf("10000次fread的fread_time =%.2lf微秒\n",fread_time);return 0;
}

fwrite和fread有自己的缓冲区,直到缓冲区写满或者指针指向文本结束位置时,才会进行一次I/O操作,大大减少了write和read函数在内核空间和用户空间之间的转换,这种转换会带来非常大的cpu开销,所以前者的效率更高。(截图如下:)

附录: multiply,使用prof/gprof测量程序运行时间

Linux/Unix环境提供了prof/gprof工具来收集一个程序各函数的执行次数和占用CPU时间等统计信息,使用prof/gprof工具查找程序性能问题,要求编译命令添加-p选项(prof)或-pg选项(gprof),程序执行时就会产生执行跟踪文件mon.out(或gmon.out),再运行prof(或gprof)程序读取跟踪数据,产生运行报告。现在用gprof对以下程序各函数运行性能(占用CPU时间)进行测量。先输入程序源代码:

#include <stdio.h>
int multiply_quick( int x, int y)
{return x * y;
}
int multiply_slow(int x,int  y)
{int i, j, k;for (i = 0, k = 0; i < x; i++)k = k + y;return k;
}
int main(int argc, char* argv[])
{int i, j;int x, y;for (i = 0; i < 1000; i++) {for (j = 0; j < 1000; j++) {x = multiply_quick(i, j);y = multiply_slow(i, j);}}printf("x=%d, y=%d\n", x, y);return 0;
}


multipy_slow花费了0.98s,multipy_quick花费了0.01s

任务4:在Linux系统环境下,编写程序task44.c,对一篇英文文章文件的英文单词词频进行统计。
(1)以“单词:次数”格式输出所有单词的词频(必做)
(2)以“单词:次数”格式、按词典序输出各单词的词频(选做)
(3)以“单词:次数”格式输出出现频度最高的10个单词的词频
例如,若某个输入文件内容为:
GNU is an operating system that is free software—that is, it respects users’ freedom.
The development of GNU made it possible to use a computer without software that would trample your freedom.
则输出应该是:
GNU:2
is:3
it:2
……

代码:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include<malloc.h>
#include<string.h>
//#include<algorithm>
//#include <unistd.h>
#define MAXSIZE 200
typedef struct Word {char word[30];      //设单词最长为30个字母int count;            //该单词出现的次数
}WordNode;
typedef struct article {WordNode Word[MAXSIZE]; //单词的集合int num;         //这篇文章不同的英文单词的种数
}Article;
void Insert_word(char* temp, Article* a) {if (a->num == MAXSIZE) {printf("单词表已经满,输入失败\n");return;}if (temp == NULL)return;if (a->num == 0) {       //情况1:单词表里暂时还没有保存单词a->Word[0].word[0] = '\0';strcpy(a->Word[0].word, temp);a->Word[0].count = 1;a->num = 1;}else {int i;for (i = 0; i < a->num; i++) {if (strcmp(temp, a->Word[i].word) == 0) {//情况2:该单词已经存在a->Word[i].count++;return;}}a->Word[a->num].word[0] = '\0';strcpy(a->Word[a->num].word, temp);         //情况2:该单词是首次输入a->Word[a->num].count = 1;a->num++;}
}
void divide_word(char* temp) {int i;if (temp == NULL) {return;}for (i = 0; temp[i] != '\0'; i++) {if (!((temp[i] >= 'A' && temp[i] <= 'Z') || (temp[i] >= 'a' && temp[i] <= 'z'))) {temp[i] = ' ';}}
}void paixu(Article* article) {int i, j;for (i = 0; i < article->num - 1; i++) {for (j = 0; j < article->num - 1 - i; j++) {if (article->Word[j].count < article->Word[j + 1].count) {WordNode temp = article->Word[j];article->Word[j] = article->Word[j + 1];article->Word[j + 1] = temp;}}}
}
void main()
{Article article = {.num=0};char temp[1000];int i;FILE* fd = fopen("./task44.txt", "r");while (!feof(fd)) {char* p;fscanf(fd, "%s", temp);divide_word(temp);       //有可能一次读入不止一个单词,所以要分隔开p = strtok(temp, " ");  //strtok把temp分成多个字符串do {Insert_word(p, &article);} while ((p = strtok(NULL, " ")) != NULL);//合适调整循环跳出条件}printf("按词典序输出,所有单词的词频如下:\n");for (i = 0; i < article.num; i++) {printf("%s:%d\n", article.Word[i].word, article.Word[i].count);}printf("\n最高词频的前十个单词:\n");paixu(&article);          //使用稳定排序法,才能符合题目要求for (i = 0; i < 10; i++) {printf("%s:%d\n", article.Word[i].word, article.Word[i].count);}}


后记

第一次写C for Linux ,特别是gcc 编译器特别不习惯,出现了很多没见过的问题。

第一个就是

段错误 (核心已转储)

这种字样,一般就是相当于vs上数组越界,访问到不合理的内存这种情况,多去留意下自己write和read这些I/O类的函数,一行行仔细比对,一定能找到问题所在。

第二个就是c语言很久没写过了,很多语法都不记得了。还犯了在结构体里初始化char数组的小失误。

第三个就是某些头文件在gcc编译器里找不到,只能自己编写成库文件,否则就只能换一个函数来使用。

收获:
read和write是要进行内核模式和用户模式之间的切换的,这种切换会带来非常大的cpu开销,所以相比之下,fwrite和fread有自己的缓冲区,缓冲区满了或文件指针结束了才进行一次读出/写入操作,效率更高。(都是二进制的读写,不适合文本数据)

fgets和fputs,可以一行行的读写,适合文本数据
当不足n个字符时,读到\n就停止,会在末尾增添\0。如果刚刚好n个字符,优先读入\0,不读入\n。

read和write:(参数)

(int fd, const void *buf, size_t nbyte)
文件描述符,缓冲区,指定I/O字节数

fread和fwrite: (参数)

(const void *ptr, size_t size, size_t nmemb, FILE *stream)
目标元素数组的指针,每个元素大小(字节),元素个数(字节),文本指针

fgets和fputs: (参数)

(char *str, int n, FILE *stream)
字符数组的指针,读取的最大字符数,文本指针

注意:FILE * 类型和int类型不相等

编译.c文件时,命令中添加-p选项(prof)或-pg选项(gprof),程序执行时就会产生执行跟踪文件mon.out(或gmon.out),再运行prof(或gprof)程序读取跟踪数据,产生运行报告。

strtok函数可以把字符串切割成若干个字符串。

任务四其实可以用字典树来做,但是很久没摸索过c语言了,实在吃力,不得不放弃了。

最后温馨提醒:以上所有代码都需要"wrapper.h"这个头文件,如果需要进行代码复用,亲手尝试代码运行结果的同学,可以私信我转发。这个头文件只是个针对课程学习内容的万能头文件,有能力的同学可以自己按需添加头文件也可,不一定需要wrapper.h

如果需要wrapper.h,可以私信我转发,但效率一般不高,如果有积分的同学可以到wrapper.h头文件CSDN下载地址https://download.csdn.net/download/enjoy_code_/12521655
自行下载,我虽然设置成了0积分,但还是被系统管理员改成了1积分,请见谅。跪谢理解。

Linux I/O编程 实验内容相关推荐

  1. 实验linux下的编程,实验四 Linux下的C语言编程;

    <实验四 Linux下的C语言编程;>由会员分享,可在线阅读,更多相关<实验四 Linux下的C语言编程;(5页珍藏版)>请在人人文库网上搜索. 1.实验四Linux 下的 C ...

  2. linux中关于ssh实验,操作系统实验三linux的telnetftpssh的相关配置及验证

    操作系统实验三linux的telnetftpssh的相关配置及验证 -1-昆明理工大学信息工程与自动化学院学生实验报告( 2010 -2011 学年第 二 学期 )课程名称:操作系统 开课实验室:信自 ...

  3. 实验六 Linux进程编程,Linux系统编程实验六:进程间通信

    <Linux系统编程实验六:进程间通信>由会员分享,可在线阅读,更多相关<Linux系统编程实验六:进程间通信(10页珍藏版)>请在人人文库网上搜索. 1.实验六:进程间通信l ...

  4. 南工程c语言实验报告,Linux环境下-C语言编程实验报告(1)(总4页).doc

    Linux环境下-C语言编程实验报告(1)(总4页).doc 西 安 邮 电 大 学 (计算机学院)课内实验报告实验名称 Linux环境下 C语言编程 专业名称 网络工程班 级 1203班 学生姓名 ...

  5. linux下的c语言编程实验4,实验四-Linux下的C语言编程

    实验四Linux 下的 C 语言编程 四.实验内容 本实验要求在LINUX/UNIX环境下用C语言编写三个具体的SHELL命令,基本涉及了LINUX/UNIX文件系统中较为常用的有关文件操作的系统调用 ...

  6. 嵌入式linux ntpd命令,嵌入式Linux网络编程之:实验内容——NTP协议实现

    本文引用地址:http://www.eepw.com.cn/article/257114.htm 10.4实验内容--NTP协议实现 1.实验目的 通过实现NTP协议的练习,进一步掌握Linux网络编 ...

  7. linux建立数列文本,Linux实验内容.doc

    于家新 燕山大学 Linux技术上机实验指导 学 院 信息科学与工程学院 年级专业 指导教师 学生 121304011231 学生姓名 提交日期 实验二 Linux常用命令使用 一.实验目的 1.掌握 ...

  8. linux系统编程界面实验报告,操作系统实验报告-Linux操作使用编程.doc

    操作系统实验报告-Linux操作使用编程 实 验 报 告( 2012/ 2013 学年 第二学期) 课程名称操 作 系 统A实验名称Linux操作.使用.编程实验时间2013年 5 月 6日指导单位计 ...

  9. linux中c语言开发实验报告,Linux下C语言编程实验报告.doc

    第五章: Linux下的C语言编程 姓名: 学号:520913080429 专业:信息安全09-04 实验内容: 1.c语言编程 2.vi编辑器 3.gcc编辑器 4.gdb编辑器 5. gdb中运行 ...

最新文章

  1. CloudFoundry命令行安装和卸载插件
  2. 461. 汉明距离 golang
  3. php网站分区,PHP - Manual: 分区和分片 (官方文档)
  4. 【数据结构与算法】堆
  5. 小米组织架构再调整:手机部成立参谋部 朱磊出任参谋长
  6. qt 程序异常结束_【心电国际指南2009专家解读】浦介麟 冉玉琴老师:QT 间期的规范化测量及其意义...
  7. C语言递归分形实验-曼德勃罗集
  8. linux复制文件中内容吗,Linux中实现对文件内容的复制。。。
  9. python新浪_Python——新浪新闻抓取
  10. 11.抓取JavaScript
  11. Mybatis源码分析(一) JDBC Mybatis 简介
  12. python判断成语是abac型_abac型词语成语大全
  13. 苹果maccms V10采集插件下载全自动配置定时任务采集教程
  14. 使用uboot + minicom串口协议下载镜像文件
  15. 在图形用户登录界面输入正确用户名与密码后,闪了一下(即将要登录进去那一刹那),它NND给我蹦出来了!
  16. 彩色图像加密matlab算法,彩色图像混沌加密算法
  17. linux永久修改dns
  18. html的css怎么设置深度,vue css 深度选择器
  19. Android手机在4G网络环境下IP的识别
  20. java excel 插件_轻量级的原生JavaScript的Excel插件——JExcel

热门文章

  1. VB.NET 通过vbs发送微信消息
  2. 三年级计算机活动记录,小学三年级主题班会活动记录
  3. 消费者人群画像—信用智能评分 比赛回顾
  4. 阿里突遭断网断电!双11最惊险一幕刚刚曝光
  5. Devexpress Xtrareport 创建主从报表
  6. 复习单片机:点亮LED(内含实物图+硬件设计+软件编程+原始代码)
  7. java 判断图片合适,Java 判断图片色彩
  8. 一个比较牛逼人的博客
  9. Redis-6.2.* 版本配置文件redis.conf详解
  10. python提取发票信息发票识别_分享一个电子发票信息提取工具(Python)