学习笔记 参考链接1 、参考链接2以及百度百科
在进行C语言学习的时候我们了解到了C语言相关的一些IO操作,如fopen,fwrite,fread,fprintf,fclose等相关函数,他们都是由C库函数提供的一些函数,是将操作系统的系统调用加以封装,虽说Linux是由C语言实现的,但为了使我们更加的了解Linux,就需要了解更接近与底层的一些IO操作,因此就需要来了解下基本的系统调用—open,write,read,close
首先我们来了解下open,write,read,close的系统调用

open

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags, mode_t mode);

open有三个参数
pathname:要打开或创建的目标文件名
flags:对文件进行多种操作也就有有多个参数,这多个参数可以进行或运算,即就是flags
参数:
O_RDONLY:只读打开
O_WRONLY:只写打开
O_RDWR:读,写打开
O_CREAT:若文件不存在,创建文件
O_APPEND:追加写
参数1,2,3,必须制定一个且只能制定一个,使用参数4,必须使用open的第三个参数mode:新文件的访问权限
返回值:成功:新打开文件的文件描述符(fd)
失败:-1

write

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

fd:文件描述符
buf:写入的缓冲区
count:写的字符长度,也就是看你需要写多少
返回值:
如果顺利write()会返回实际写入的字节数。当有错误发生时则返回-1,错误代码存入errno中。
read

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);

fd:文件描述符
buf:读入的缓冲区
count:写的字符长度,也就是看你需要写多少
返回值
如果顺利read()会返回实际写入的字节数。当有错误发生时则返回-1,错误代码存入errno中。
close

#include <unistd.h>
int close(int fd);

close的参数就相对简单了,这一个操作是不能遗漏的,只要了使用fd就必须close它
在这几个函数中都涉及到了关键的参数fd,因此要了解这几个函数,就必须先了解下文件描述符(fd)。
什么是文件描述符,这是一个相对抽象的概念,我们先来看看下面这张图

在PCB结构体中存在一个files指针,它指向一个file_struct结构体,而在file_struct结构体中存在一个file* fd数组,这个数组里面存放的是file指针,用来指向不同的file文件,而fd就可以理解为这个指针数组的下标,因此要打开一个文件,我们就可以拿到该文件的fd就可以了。
fd的分配原则:
files_struct数组当中,使用没有被使用的最小下标,作为新的文件描述符。
操作系统默认使用了该数组的前三个元素,0号下标指向标准输入(stdin),1号下标指向标准输出(stdout),2号下标指向标准错误(stderr)。
因此正常情况下,新的fd都是从3开始的,但如果我们关闭了默认的fd,新的文件的fd就从关闭的fd处开始。
说到了fd,我们就不得不来区分下FILEfd
FILE是C库当中提供的一个结构体,而fd是系统调用,更加接近于底层,因此FILE中必定封装了fd。
我们可以来看看FILE的结构体:
typedef struct _IO_FILE FILE;在/usr/include/stdio.h
它的结构体中有这么一段

struct _IO_FILE {int _flags;       /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags//缓冲区相关/* The following pointers correspond to the C++ streambuf protocol. *//* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */char* _IO_read_ptr;   /* Current read pointer */char* _IO_read_end;   /* End of get area. */char* _IO_read_base;  /* Start of putback+get area. */char* _IO_write_base; /* Start of put area. */char* _IO_write_ptr;  /* Current put pointer. */char* _IO_write_end;  /* End of put area. */char* _IO_buf_base;   /* Start of reserve area. */char* _IO_buf_end;    /* End of reserve area. *//* The following fields are used to support backing up and undo. */char *_IO_save_base; /* Pointer to start of non-current get area. */char *_IO_backup_base;  /* Pointer to first valid character of backup area */ char *_IO_save_end; /* Pointer to end of non-current get area. */struct _IO_marker *_markers;struct _IO_FILE *_chain;int _fileno;//fd的封装

可以看到int_fileno就是对fd的封装,在这一部分的开头有一大段跟缓冲区相关的内容,为什么要诺列出它呢,首先可以来看一个很诡异的例子:

#include <stdio.h>                                                            #include <string.h>#include <unistd.h>#include <sys/stat.h>#include <sys/types.h>#include <fcntl.h>int main(){const char *msg1 = "hello printf\n";const char *msg2 = "hello fwrite\n";const char *msg3 = "hello write\n";printf(msg1);fwrite(msg2, 1, strlen(msg2), stdout);write(1, msg3, strlen(msg3));fork();return 0;}

运行结果:

[rlh@localhost test]$ ./hello
hello printf
hello fwrite
hello write

但当我们对进程实现输出重定向,你就会发现诡异的事情:

[rlh@localhost test]$ ./hello > file
[rlh@localhost test]$ cat file
hello write
hello printf
hello fwrite
hello printf
hello fwrite

这是为什么呢,这是跟C库的缓冲数据有关,C库缓冲数据分为三种(1)、无缓冲(2)、行缓冲(3)、全缓冲。

行缓冲就是往显示器上写,全缓冲就是往文件里写。

在上面的现象中,write不受影响是因为它属于系统调用,没有缓冲区,而printf和fwrite会自带缓冲区,当发生重定向到普通文件的时候,它就会从行缓冲转变为全缓冲,也就是会往文件里面写写,但是我们缓冲区里的数据,即使fork也不会立即被刷新,当进程退出后会统一刷新,写入文件,但是fork的时候会发生写时拷贝,也就是当父进程准备刷新的时候,子进程就已经有了一份相同的数据,所以就会产生上面的现象。

了解下重定向。
重定向分为三种:
输出重定向(>) 也就是关闭fd为1下标所指向的内容
输入重定向(<) 同理就是关闭fd为0下标所指向的内容
追加重定向(>>) 后面多一个追加选项

stat函数

#include <sys/stat.h>
#include <unistd.h>
int stat(const char *file_name, struct stat *buf);

函数说明: 通过文件名filename获取文件信息,并保存在buf所指的结构体stat中
返回值: 执行成功则返回0,失败返回-1,错误代码存于errno

错误代码:
ENOENT 参数file_name指定的文件不存在
ENOTDIR 路径中的目录存在但却非真正的目录
ELOOP 欲打开的文件有过多符号连接问题,上限为16符号连接
EFAULT 参数buf为无效指针,指向无法存在的内存空间
EACCESS 存取文件时被拒绝
ENOMEM 核心内存不足
ENAMETOOLONG 参数file_name的路径名称太长
eg:

#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>int main() {struct stat buf;stat("/etc/hosts", &buf);printf("/etc/hosts file size = %d/n", buf.st_size);
}
struct stat {dev_t         st_dev;       //文件的设备编号ino_t         st_ino;       //节点mode_t        st_mode;      //文件的类型和存取的权限nlink_t       st_nlink;     //连到该文件的硬连接数目,刚建立的文件值为1uid_t         st_uid;       //用户IDgid_t         st_gid;       //组IDdev_t         st_rdev;      //(设备类型)若此文件为设备文件,则为其设备编号off_t         st_size;      //文件字节数(文件大小)unsigned long st_blksize;   //块大小(文件系统的I/O 缓冲区大小)unsigned long st_blocks;    //块数time_t        st_atime;     //最后一次访问时间time_t        st_mtime;     //最后一次修改时间time_t        st_ctime;     //最后一次改变时间(指属性)
};

先前所描述的st_mode 则定义了下列数种情况:

 S_IFMT   0170000    文件类型的位遮罩S_IFSOCK 0140000    scoketS_IFLNK 0120000     符号连接S_IFREG 0100000     一般文件S_IFBLK 0060000     区块装置S_IFDIR 0040000     目录S_IFCHR 0020000     字符装置S_IFIFO 0010000     先进先出S_ISUID 04000     文件的(set user-id on execution)位S_ISGID 02000     文件的(set group-id on execution)位S_ISVTX 01000     文件的sticky位S_IRUSR(S_IREAD) 00400     文件所有者具可读取权限S_IWUSR(S_IWRITE)00200     文件所有者具可写入权限S_IXUSR(S_IEXEC) 00100     文件所有者具可执行权限S_IRGRP 00040             用户组具可读取权限S_IWGRP 00020             用户组具可写入权限S_IXGRP 00010             用户组具可执行权限S_IROTH 00004             其他用户具可读取权限S_IWOTH 00002             其他用户具可写入权限S_IXOTH 00001             其他用户具可执行权限

上述的文件类型在POSIX中定义了检查这些类型的宏定义:

    S_ISLNK (st_mode)    判断是否为符号连接S_ISREG (st_mode)    是否为一般文件S_ISDIR (st_mode)    是否为目录S_ISCHR (st_mode)    是否为字符装置文件S_ISBLK (s3e)        是否为先进先出S_ISSOCK (st_mode)   是否为socket

linux系统调用open、write、close、read以及stat函数详解相关推荐

  1. linux中recvfrom读取速度,Linux系统调用-- recv/recvfrom 函数详解

    Linux系统调用-- recv/recvfrom函数详解 功能描述: 从套接字上接收一个消息.对于recvfrom,可同时应用于面向连接的和无连接的套接字.recv一般只用在面向连接的套接字,几乎等 ...

  2. linux 系统函数调用脚本文件,Linux系统调用fsync函数详解

    Linux系统调用fsync函数详解 发布时间:2013-11-14 19:55:10   作者:佚名   我要评论 Linux fsync函数主要用于将同步内存中所有已修改的文件数据到储存设备,多用 ...

  3. Linux系统调用-- recv/recvfrom/recvmsg函数详解(转)

    Linux系统调用-- recv/recvfrom/recvmsg函数详解 2007-09-10 23:37 [recv/recvfrom/recvmsg系统调用]   功能描述: 从套接字上接收一个 ...

  4. linux内核 recvfrom,Linux系统调用-- recv/recvfrom 函数详解

    Linux系统调用-- recv/recvfrom函数详解 功能描述: 从套接字上接收一个消息.对于recvfrom,可同时应用于面向连接的和无连接的套接字.recv一般只用在面向连接的套接字,几乎等 ...

  5. linux系统四个组成部分,Linux系统由哪几部分组成?系统详解(干货)

    原标题:Linux系统由哪几部分组成?系统详解(干货) 我们常说的Linux一般指的是系统内核,基于Linux系统内核的操作系统叫Linux发行版操作系统,像redhat.centos.ubuntu和 ...

  6. 系统调用功能号与execve函数详解

    先看看下面通过系统调用实现的hello world代码: .section .data msg:.ascii "Hello world!\n" .section .text .gl ...

  7. Linux 文件锁 fcntl 函数详解

    Linux 文件锁 fcntl 函数详解 #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd); ...

  8. Linux中fork()函数详解

    Linux中fork()函数详解 一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事, ...

  9. linux 中 sigaction 函数详解

    linux 中 sigaction 函数详解 一.函数原型 sigaction 函数的功能是检查或修改与指定信号相关联的处理动作(可同时两种操作) int sigaction(int signum, ...

  10. linux内核中send与recv函数详解

    Linux send与recv函数详解 1.简介 #include <sys/socket.h> ssize_t recv(int sockfd, void *buff, size_t n ...

最新文章

  1. 昨日,全球股市进入ICU!89岁股神巴菲特惊叹活久见!苹果微软万亿美金市值摇摇欲坠...
  2. BigGAN被干了!DeepMind发布LOGAN:FID提升32%,华人一作领衔
  3. 【数据挖掘笔记四】数据仓库和联机分析处理
  4. 谷歌chrome浏览器的源码分析(二)
  5. java连接stk外部接口_SLWSTK无线开发工具上的外扩串口如何使用(虚拟串口/VCOM)...
  6. 数学--数论--(逆元)扩展欧几里求解+证明
  7. DataGridView控件中显示图片及其注意事项 【z】
  8. 产品人如何在小企业中夹缝生存?
  9. oracle11g 安装报告,[数据库]oracle11g的standby性能分析报告statpack安装_星空网
  10. 电大计算机基础知识机考题,电大《计算机应用基础》网考机考单选题大汇总
  11. python面向对象编程指南 豆瓣_一文看懂Python面向对象编程(Python学习与新手入门必看)-绝对原创...
  12. word导入文献-mendeley
  13. 20191001每日一句
  14. [Java面试十]浏览器跨域问题.
  15. supersu二进制更新安装失败_supersu 二进制更新解决方法
  16. Typora高亮颜色设置
  17. CSK与DCSK调制与解调
  18. java中将毫秒值转换为小数点形式(几点几格式)的方法
  19. 执行才是王道,如何提升执行力
  20. 阿里巴巴开发手册之应用分层

热门文章

  1. PHP中怎样实现正负数的相加,PHP 求任意n个正负整数里面最大的连续和
  2. linux中第一个进程的形成,Linux进程管理
  3. 计算机网络和通信,计算机网络与通信技术
  4. linux cpu负载巡检,linux服务器巡检报告.doc
  5. easyui树形菜单实现
  6. CSS3总结(干货)
  7. JS中的兼容问题总结
  8. ESLint共享配置的两种方式eslint-plugin和eslint-config
  9. sessionStorage什么时候失效
  10. 备忘录——通过RVA计算文件位置