2017-2018-1 20155326 《信息安全系统设计基础》第四周学习总结
要求
补充完成课上没有完成的内容(2分)
学习教材附录A,第十章内容
参考别出心裁的Linux系统调用学习法,学习视频,掌握两个重要命令:
man -k key1 | grep key2| grep 2 : 根据关键字检索系统调用
grep -nr XXX /usr/include :查找宏定义,类型定义
完成head,tail的使用,相关API的分析,伪代码,产品代码,测试代码的编写(3分)
改写myod
1 参考教材第十章内容
2 用Linux IO相关系统调用编写myod.c 用myod XXX实现Linux下od -tx -tc XXX的功能,注意XXX是文件名,通过命令行传入,不要让用户输入文件名
3 不要把代码都写入main函数中
4 要分模块,不要把代码都写入一个.c中
题目分析
将原来myod 的标准I/O函数改写为系统调用来访问的I/O
1.fopen换成系统调用的open
标准I/O使用fopen函数打开一个文件:
FILE* fp=fopen(const char* path,const char*mod)
其中path是文件名,mod用于指定文件打开的模式的字符串,比如"r","w","w+","a"等等,可以加上字母b用以指定以二进制模式打开(对于Linux系统,只有一种文件类型,因此没有区别),如果成功打开,返回一个FILE文件指针,如果失败返回NULL,这里的文件指针并不是指向实际的文件,而是一个关于文件信息的数据包,其中包括文件使用的缓冲区信息。
Linux系统使用open函数用于打开一个文件:
int fd=open(char *name,int how);
与fopen类似,name表示文件名字符串,而how指定打开的模式:O_RDONLY(只读),O_WRONLY(只写),O_RDWR (可读可写),还有其他模式请man 2 open。成功返回一个正整数称为文件描述符,这与标准I/O显著不同,失败的话返回-1,与标准I/O返回NULL也是不同的。
2将fgets改变成系统调用的read
fgets使用三个参数:
char* fgets(char *s, int size, FILE *stream);
第一个参数和gets一样,用于存储输入的地址,第二个参数为整数,表示输入字符串的最大长度,最后一个参数就是文件指针,指向要读取的文件。最后是fscanf,与scanf类似,只不过增加了一个参数用于指定操作的文件,比如fscanf(fp,"%s",words)
Linux系统中使用read函数用于读取open函数打开的文件,函数原型如下:
ssize_t numread=read(int fd,void*buf,size_t qty);
其中fd就是open返回的文件描述符,buf用于存储数据的目的缓冲区,而qty指定要读取的字节数。如果成功读取,就返回读取的字节数目(小于等于qty)。
3将fclose改变成close
,标准I/O使用fclose关闭文件,将文件指针传入即可,如果成功关闭,返回0,否则返回EOF
比如:
if(fclose(fp)!=0)
printf("Error in closing file");
而Linux使用close用于关闭open打开的文件,与fclose类似,只不过当错误发生时返回的是-1,而不是EOF,成功关闭同样是返回0。
代码如下:
#include "head.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define SIZE 100
int main(int argc,char *argv[]) {
int fd=open(argv[3],O_RDONLY,0);
char ch[SIZE];
int length = read(fd,&ch,SIZE);
close(fd);
ascii(ch,length);
return 0; }
题目结果:
教材知识总结
打开和关闭文件
进程是通过调用open函数来打开一个已存在的文件或者创建一个新文件:
- flags参数表示进程打算如何访问这个文件,它的值包括:
O_RDONLY:只读
O_WRONLY:只写
O_RDWR:可读可写
mode参数指定了新文件的访问权限位。作为上下文的一部分,每个进程都有一个umask它是通过调用umask函数来设置的。
读和写文件
应用程序是通过分别调用系统函数 read和write函数来执行输入和输出的。
- read和write传送的字节比应用程序要求的要少。这些不足值不表示有错误。出现这种情况的可能的原因有:
读时遇到EOF
从终端读文本行
读和写网络套接字
rio的无缓冲的输入输出函数
通过调用rio_readn和rio_writen函数,应用程序可以在储存器和文件之间直接传送数据。
rio_readn函数从描述符fd的当前文件位置最多传送n个字节到存储器位置usrbuf。类似的rio_writen函数从位置usrbuf传送n个字节到描述符fd。rio_readn函数在遇到EOF时只能返回一个不足值。rio_writen函数绝不会返回不足值。
rio的带缓冲的输入函数
在带缓冲区的版本中,每打开一个描述符都会调用一次rio_readinitb函数,它将描述符fd和地址rp处的一个类型为rio_t的读缓冲区联系起来。
rio_readinitb函数从文件rp读取一个文本行(包括结尾的换行符),将它拷贝到存储器位置usrbuf,并且用空字符来结束这个文本行。
RIO读程序的核心是rio_read函数,rio_read函数可以看成是Unix read函数的带缓冲区的版本。当调用rio_read要求读取n个字节的时候,读缓冲区内有rp->rio_cnt个未读的字节。如果缓冲区为空的时候,就会调用read系统函数去填满缓冲区。这个read调用收到一个不足值的话并不是一个错误,只不过读缓冲区的是填充了一部分。
一旦缓冲区非空,rio_read就从读缓冲区拷贝n和rp->rio_cnt中较小值个字节到用户缓冲区,并返回拷贝字节的数目。
对于应用程序来说,rio_read和系统调用read有着相同的语义。出错时返回-1;在EOF时,返回0;如果要求的字节超过了读缓冲区内未读的字节的数目,它会返回一个不足值。rio_readlineb函数多次调用rio_read函数。每次调用都从读缓冲区返回一个字节,然后检查这个字节是否是结尾的换行符。
读取文件元数据
应用程序能够通过调用stat和fstat函数,检索到关于文件的信息。(有时也称为元数据。)
stat函数以一个文件名作为输入,填写如图数据结构中的各个成员。
st_size成员包含了文件的字节数大小。st_mode成员则编码了文件访问许可位和文件类型。Unix识别大量不同的文件类型。普通文件包括某种类型的二进制或文本数据。对于内核而言,文本文件和二进制文件毫无区别。
掌握两个重要命令
-
man -k key1 | grep key2| grep 2 : 根据关键字检索系统调用
-
grep -nr XXX /usr/include :查找宏定义,类型定义
完成head,tail的使用,相关API的分析,伪代码,产品代码,测试代码的编写
head
head功能:head的功能是显示一个文件前十行的内容
-伪代码
循环打印出每行内容直至第十行
关闭文件,结束````
- 代码:
````#include
void main()
{
int i,n;
char buf[500];
FILE *fp;
if((fp=fopen("test.txt","rt"))==NULL)
{
printf("cannot open file
");
return;
}
for(i=0;i<10;i++){
fscanf(fp,"%[^
]%*c",buf);
printf("%s
", buf);
}
fclose(fp);
}````
####tail
功能:显示打开文件的后10行内容
![](http://images2017.cnblogs.com/blog/1071551/201712/1071551-20171207013617894-1797258244.png)
- 伪代码
打开文件
找到文件后十行
循环打印出每行内容直至结束
关闭文件,结束
- 代码:
#include
void main()
{
int i,n;
char buf[500];
FILE fp;
int num=0;
if((fp = fopen("test.txt","rt")) == NULL)
{
perror("fail to read");
return;
}
while(fgets(buf,500,fp) != NULL)
{
num++;
}
rewind(fp);
n=num-10;
for(i=0;i<n;i++)
{
fscanf(fp,"%[^
]%c");
}
for(i=n;i<num;i++)
{
fscanf(fp,"%[^
]%c",buf);
printf("%s
",buf);
}
fclose(fp);
}