Linux基础IO

1.练习open/read/write/close等文件相关系统调用接口,纵向对比fd与FILE结构体 

open

#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>

int open(const char *pathname,int flags);
int open(coonst char *pathname,int flag,mode_t mode);
pathname:要打开或创建的目标文件
flags:打开文件时,可以传入多个参数选项,用下面一个或多个常量进行“或”运算,构成flags
    参数:
        O_RDONLY : 只打开
        O_WRONLY : 只写打开
        O_RDWR   : 读,写打开
                    这三个常量,必须指定一个且只能指定一个
        O_CREAT  : 若文件不存在,则创建它,需要使用mode选项,来指明新文件的访问权限

write

size_t write(int fd,const void *buf,size_t nbyte)
参数:
    fd:文件描述符
    buf:指定的缓冲区,即要写入的指针
    nbyte:要写入文件指定的字节数
返回值:
    成功返回写的字节数,失败返回-1

read

size_t read(int fd,const void *buf,size_t nbyte)
参数:
    fd:文件描述符
    buf:指定的缓冲区
    nbyte:要读取文件指定的字节数
返回值:
    成功时返回读取到的字节数(为零表示读到文件描述符),此返回值受文件剩余字节数限制,当返回值小于指定的字节数(比如已经接近文件结尾,或者正在从管道或者终端读取数据,或者read()被信号中断),发生错误时返回-1。

close

int close(int fd);
参数:
    fd:文件标识符
返回值:
    成功返回0,失败返回-1


fd:文件描述符(OS层)

fd只是一个整数,在open时产生。起到一个索引的作用,进程通过PCB中的文件描述符表找到该fd所指向的文件指针file,因此在Linux系统下面,文件描述符主要是被用来标识一个文件。内核通过文件对象表来管理系统中各种各样的文件,而文件表则是通过指针来指向打开的文件,进而达到管理整个文件系统的目的。

   FILE:文件指针(lib层,即C库)
1
C中使用文件指针来做为I/O的句柄,文件指针指向进程的用户空间中的一个FILE机构体//C语言文件指针域文件描述符之间可以相互转换

int fileno(FILE * stream)
FILE * fdopen(int fd, const char * mode)

struct _iobuf {
    char *_ptr;          //缓冲区当前指针
    int   _cnt;
    char *_base;         //缓冲区基址
    int   _flag;         //文件读写模式
    int   _file;         //文件描述符
    int   _charbuf;      //缓冲区剩余自己个数
    int   _bufsiz;       //缓冲区大小
    char *_tmpfname;
};
typedef struct _iobuf FILE;


 

2.对之前编写的自主shell进行修改,使其支持输入/输出/追加重定向 

我们知道对于Linux来说,shell就是一个命令行解释器,当我们输入相关的命令,会去执行相关的操作。 
比如当我们在输入ls -a -l命令,shell就会打印出当前目录的内容,这是如何实现的呢,shell自己就是一个进程,当我们输入类似于ls的命令,它会通过fork,exec去创建一个新的子进程去执行相关操作,因此我们可以利用这个来实现一个简单的shell,当然这个shell足够的简单,并不像Linux内置的shell功能那么强大,支持各种操作,报错等等。 
我们先来再聊聊如何去实现一个shell? 
1、首先是提示符,root@host以及当前路径,我们可以使用调用系统api直接打印,这里为了方便,我直接用printf函数打印。 
2、解析命令,对于ls -a -l这种操作,我们只需要存入到指针数组中,char* shell_argv[32],ls存到shell_argv[0]当中,-a存到shell_argv[1],-l存到shell_argv[2]……………最后设置为一个NULL 
3、利用execvp进行调用新的程序。 
代码如下:


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <string.h>
#include <ctype.h>//isspace函数的头文件
#include <fcntl.h>


int main(){
    for(;;)
    {
    printf("myshell@host:");
    fflush(stdout);//
    //解析输入到shell上的字符串 ls -a -l
    char buffer[1024];
    int read_size=read(1,buffer,sizeof(buffer));
        if(read_size>0){
            buffer[read_size-1]=0;
        }
        char *shell_argv[32]={NULL};
        int shell_index=0;
        char *start=buffer;
        while(*start!='\0'){
            while(*start!='\0'&& isspace(*start)){
            *start='\0';
            start++;
            }
            shell_argv[shell_index++]=start;
            while(*start!='\0' && !isspace(*start)){//
            start++;
            }
        }
        //创建子进程的exec
        pid_t pid=vfork();
        if(pid<0){
            printf("vfork failure\n");
            exit(1);
        }
        else if(pid==0){
            //考虑重定向
            //从字符串数组中找重定向标志
          int i=0;
          int flag=0;
          for(;shell_argv[i]!=NULL;++i){
              if(strcmp(">",shell_argv[i])==0){
              flag=1;
              break;
              }
          }
          int copyfd;
          shell_argv[i]=NULL;
          if(flag)
          {
              if(shell_argv[i+1]==NULL){
              printf("command error\n");
              exit(1);
              }
              close(1);
           int fd=open(shell_argv[i+1],O_WRONLY | O_CREAT,0777);
           copyfd=dup2(1,fd);//把标准输出重新定向到一个文件中
          }
          execvp(shell_argv[0],shell_argv);
          if(flag){
              close(1);
              dup2(copyfd,1);
          }
          exit(1);
        }
        else //father process
                 {
             int status=0;
             int ret=waitpid(pid,&status,0);
             if(ret==pid){
             if(WIFEXITED(status)){
             }
             else if(WIFSIGNALED(status)){
                 printf("signal is %d\n",WTERMSIG(status));
             }
             }
                  }
          }
    return 0;
}

3.编写简单的add/sub/mul/div函数,并打包成动/静态库,并分别使用。 

​
//代码
add.h
#ifndef _ADD_H
#define _ADD_H
int myadd(int x,int y);
#endif
add.c
#include<stdio.h>
#include"add.h"
int myadd(int x,int y)
{
    return x+y;
}
sub.h
#ifndef _SUB_H
#define _SUB_H
int mysub(int x,int y);
#endif
sub.c
#include<stdio.h>
#include"sub.h"
int mysub(int x,int y)
{
    return x-y;
}
mul.h
#ifndef _MUL_H
#define _MUL_H
int mymul(int x,int y);
#endif
mul.c
#include<stdio.h>
#include"mul.h"
int mymul(int x,int y)
{
    return x*y;
}
div.h
#ifndef _DIV_H
#define _DIV_H
int mydiv(int x ,int y);
#endif
div.c
#include<stdio.h>
#include"div.h"
int mydiv(int x,int y)
{
    return x/y;
}
test.c
#include<stdio.h>
#include"add.h"
#include"sub.h"
#include"mul.h"
#include"div.h"
int main()
{
    int x = 10;
    int y = 20;
    int c = myadd(x,y);
    int h = mysub(x,y);
    int m = mymul(x,y);
    int d = mydiv(x,y);
    printf("%d\t%d\t%d\t%d\n",c,h,m,d);
    return 0;
}

​


静态库:生成

[root@lrs lib.a]# gcc -c add.c -o add.o
[root@lrs lib.a]# gcc -c sub.c -o sub.o
[root@lrs lib.a]# gcc -c mul.c -o mul.o
[root@lrs lib.a]# gcc -c div.c -o div.o
[root@lrs lib.a]# ar -rc libmymath.a  add.o sub.o mul.o div.o
[root@lrs lib.a]# ls
add.c  add.h  add.o  div.c  div.h  div.o  libmymath.a  mul.c  mul.h  mul.o  sub.c  sub.h  sub.o  test.c


静态库:使用

[root@lrs lib.a]# mkdir test
[root@lrs lib.a]# cd test/
[root@lrs test]# cp ../*.h .
[root@lrs test]# ls
add.h  div.h  mul.h  sub.h
[root@lrs test]# cp ../test.c .
[root@lrs test]# ls
add.h  div.h  mul.h  sub.h  test.c
[root@lrs test]# cp ../libmymath.a  .
[root@lrs test]# ls
add.h  div.h  libmymath.a  mul.h  sub.h  test.c


新建一个文件test,将所有的头文件和test.c文件和libmymath.a文件拷贝至test文件,

[root@lrs test]# gcc test.c -L. -lmymath


//生成可执行的a.out文件

[root@lrs test]# ls
add.h  a.out  div.h  libmymath.a  mul.h  sub.h  test.c


-L:指定库路径

-l:指定库名

动态库:生成

[root@lrs lib.so]# ls
add.c  add.h  div.c  div.h  mul.c  mul.h  sub.c  sub.h  test.c
[root@lrs lib.so]# gcc -fPIC -c add.c sub.c mul.c div.c
[root@lrs lib.so]# gcc -shared -o libmymath.so *.o
[root@lrs lib.so]# ls
add.c  add.h  add.o  div.c  div.h  div.o  libmymath.so  mul.c  mul.h  mul.o  sub.c  sub.h  sub.o  test.c


shared:表示生成共享库格式

fPIC:产生位置无关码

库名规则:libxxx.so

l:链接动态库,只要库名即可(去掉lib及版本号)

L:链接库所在路径

动态库:使用

将此目录下的libmymath.so文件拷贝至/usr/lib目录下

[root@lrs lib]# cp /home/duyuetao/code/practice/code/lib.so/libmymath.so  .
[root@lrs lib]# ls
alsa      debug      gcc         java-1.7.0   jvm-exports  libmymath.so    mozilla         sendmail      
binfmt.d  dracut     grub        java-1.8.0   jvm-private  locale          NetworkManager  cpp      
[root@lrs lib.so]# gcc test.c -lmymath
[root@lrs lib.so]# ls
add.c  add.h  add.o  a.out  div.c  div.h  div.o  libmymath.so  mul.c  mul.h  mul.o  sub.c  sub.h  sub.o  test.c

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值