系统级I/O

输入/输出( I /O)是在主存和外部设备(例如磁盘驱动器、终端和网络)之间复制数据的过程。输入操作是从I/O设备复制数据到主存,而输出操作是从主存赋值数据到I/O设备。

Unix I/O

所有I/O设备(例如网络、磁盘和终端)都被模型化为文件,而所有的输入和输出都被当做对相应文件的度和写来执行。这种设备优雅地映射为文件的方式,允许Linux内核引出一个简单、低级的应用接口,称为Unix I/O,使得所有的输入和输出都能以一种统一且一致的方式来执行。

  • Linux shell 创建的么个进程开始时都有三个打开的文件:标准输入(描述符为0)(键盘)、标准输出(描述符为1)(显示器)、标准错误(描述符为2)。头文件**<unistd.h>**定义了常量STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO,它们可用来代替显示的描述符值。
  • 读文件:由指定文件读取到内存。
  • 写文件:由内存写到指定文件。

文件

在Linux下一切皆文件!

  • 普通文件:包含任意数据。
  • 目录:包含一组链接(即文件夹)的文件。
  • 套接字:用来与另一个进程进行跨网络通信的文件。
  • Linux内核将所有文件都组织成一个目录层次结构,由名为 / 的根目录确定。系统中的每个文件都是根目录的直接间接的后代。

文件的基本操作

文件的基本操作:open、close、read、write、lseek等
  • 打开(open):进程通过调用open函数来打开一个已存在的文件,若要打开的文件不存,则创建一个新文件。
    • open函数将filename转换为一个文件描述符,并且返回描述符数字。
    • flags参数:
      • O_RDONLY(只读)
      • O_WRONLY(只写)
      • O_RDWR(可读可写)
      • O_CREAT(如果文件不存在就创建它的一个截断的空文件)
      • O_TRUNC(如果文件已经存在就截断它)
      • O_APPEND(在每次写操作前,设置文件位置到文件的结尾处)
    • open函数调用:
     #include <sys/types.h>
     #include <sys/stat.h>
     #include <fcntl.h>
     
     int open(char *filename , int flags , mode_t mode);
    
  • 关闭(close):进程通过调用close函数关闭一个打开的文件。
    • close函数调用:
    #include <unistd.h>
    int close(int fd);
    
  • 读和写文件(read & write):应用程序是通过分别调用read和write函数来执行输入和输出的。
    • read函数从描述符为fd的当前文件位置复制最多n个字节到内存位置buf。返回值为-1表示一个错误,返回值为0表示EOF。若不为-1也不为0 ,则代表实际传送的字节数量。
    • write函数从内存位置buf复制至多n个字节到描述符fd的当前文件位置。
    • read、close函数调用:
    #include <unistd.h>
    ssize_t read(*int fd , void *buf , size_t n);
    ssize_t write(int fd , const void *buf , size_t n);
    

代码实例

代码(一)
/* $begin cpstdin */
#include "csapp.h"

int main(void) 
{
    char c;

    while(Read(STDIN_FILENO, &c, 1) != 0) 
	Write(STDOUT_FILENO, &c, 1);
    exit(0);
}
运行结果:

结果分析:
  • 该程序为一个循环读入,数据从标准输入STDIN_FILENO(键盘)当中输入并读取,每输入一个字符的,就自动读取一个字符到缓冲区中,若输入为 \n 则输出所有缓冲区的内容到标准输出STDOUT_FILENO(屏幕)。
代码(二)
/* $begin statcheck */
#include "csapp.h"

int main (int argc, char **argv) 
{
    struct stat stat;
    char *type, *readok;

    /* $end statcheck */
    if (argc != 2) {
		fprintf(stderr, "usage: %s <filename>\n", argv[0]);
		exit(0);
    }
    /* $begin statcheck */
    Stat(argv[1], &stat);
    if (S_ISREG(stat.st_mode))     /* Determine file type */
		type = "regular";
    else if (S_ISDIR(stat.st_mode))
		type = "directory";
    else 
		type = "other";
    if ((stat.st_mode & S_IRUSR)) /* Check read access */
		readok = "yes";
    else
		readok = "no";

    printf("type: %s, read: %s\n", type, readok);
    exit(0);
}
结果分析:
  • 应用程序通过调用stat、fstat函数,检索到关于文件的信息。若成功则返回0,若出错返回-1。

  • 函数调用:

    #include <unistd.h> 
    #include <sys/stat.h>
    int stat(const char *filename , struct stat *buf);
    int fstat(int fd , struct stat *buf);
    
  • Linux在sys/stat.h中定义了宏谓词来确定st-mode成员的文件类型:
    S_ISREG(m):是否为普通文件,为真则为普通文件。
    S_ISDIR(m):是否为目录文件,为真则为目录文件。
    S_ISSOCK(m):是否为网络套接字,为真则为网络套接字。

代码(三)
#include "csapp.h"

int main(int argc, char *argv[])
{
    int fd1, fd2, fd3;
    char c1, c2, c3;
    char *fname = argv[1];
    fd1 = Open(fname, O_RDONLY, 0);
    fd2 = Open(fname, O_RDONLY, 0);
    fd3 = Open(fname, O_RDONLY, 0);
    dup2(fd2, fd3);

    Read(fd1, &c1, 1);
    Read(fd2, &c2, 1);
    Read(fd3, &c3, 1);
    printf("c1 = %c, c2 = %c, c3 = %c\n", c1, c2, c3);

    Close(fd1);
    Close(fd2);
    Close(fd3);
    return 0;
}

在这里插入图片描述

运行结果:

在这里插入图片描述

结果分析:
  • I/O重定向
    #include <unistd.h>
    int dup2(int oldfd, int newfd);
    
    • 若成功则为非负的描述符,若出错则为-1。
    • dup2函数复制描述符表表项newfd,覆盖描述符表表项newfd以前的内容。如果newfd以及打开了,dup2会在复制oldfd之前关闭newfd。
      在这里插入图片描述

代码(四)

命令:ls -l
用于:查看列表详细内容

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值