linux系统提供的接口函数-系统IO(一)


由linux系统提供的接口函数我们称之为系统IO。

1 open 打开或者创建一个文件

NAME
open, openat, creat - open and possibly create a file

SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

参数列表:
pathname: 路径+名字 路径名 ,你要打开的文件的路径名

flags: 打开文件时的标志
1)O_RDONLY :只读
2)O_WRONLY :只写
3)O_RDWR :可读可写
以上三个选项必须选择一个并且只能选择一个。

O_APPEND :追加方式打开文件,打开文件后,文件光标在文件的末尾。
O_CREAT : 创建方式打开文件,如果文件不存在 ,则先创建它再打开 。
O_TRUNC : 截短标志, 假如文件存在, 并且是普通文件, 而且打开方式是O_WRONLY or O_RDWR, 则清空文件的内容;如果是O_RDONLY 则O_TRUNC不会生效。
O_NONBLOCK: 非阻塞的方式打开文件 。
​       非阻塞:不等待。
​             如果文件没有内容可读 read就不会阻塞, 直接返回一个错误码。
​             如果文件没有空间可写 write就不会阻塞 ,直接返回一个错误码。
​       阻塞:等待 。(默认阻塞等待打开文件)
​             如果文件没有内容可读 read就会阻塞(直到有数据可读或者出错)
​             如果文件没有空间可写 write就会阻塞(直到有空间可写或者出错)
​ …
如果有多个选项,则选项用 | 连接“位或”。

mode: 当创建文件时,也就是第二个参数中有O_CREAT选项时,才需要第三个参数 。
            如果不是创建文件 ,那么第三个参数可以忽略。
第三个参数用于指定新创建的文件的权限, 有两种方式来指定:
     a.宏
        S_IRWXU : 用户可读可写可执行权限
        S_IRUSR :用户可读
        S_IWUSR :用户可写
        S_IXUSR : 用户可执行
        S_IRWXG : 组用户可读可写可执行
        S_IRGRP…
        S_IWGRP
        S_IXGRP
        S_IRWXO :其它用户可读可写可执行
        S_IROTH …
        S_IWOTH
        S_IXOTH
        如: S_IRUSR | S_IRGRP | S_IROTH
        ==> r–r–r–
    b.用八进制来表示
        如:0666 => 110110110 rw-rw-rw-

返回值:

​         成功返回一个打开的文件的文件描述符 (>2)
​         因为操作系统会自动地为每个进程打开三个文件
​         标准输入文件 文件的描述符 STDIN_FILENO 0
​         标准输出文件 文件的描述符 STDOUT_FILENO 1
​         标准出错文件 文件的描述符 STDERR_FILENO 2

​         失败返回-1,同时errno被设置。

以上例子中 ,一旦open出错, 将会返回-1,但是我们并不知道什么原因导致open出错了。 如果要知道出错的原因 ,我们就需要用到我们的errno了。errno是一个全局变量 ,定义在errno.h里面。它被用来保存最后一个出错的出错码,提供了另外一个函数, 用来解析出错码对应的出错原因。 perror把出错码对应的提示打印出来。

     perror("open error")

2 read从一个打开的文件中读取数据

NAME
read - read from a file descriptor

SYNOPSIS
#include <unistd.h>

​ ssize_t read(int fd, void *buf, size_t count);

参数列表:
fd:文件描述符,表示你要从哪个文件里面读取数据 ,open函数的返回值。
buf:指向一段内存的首地址 ,这段空间用来保存从文件中读到的数据 。
count:表示你要从fd中读取多少个字节的数据。
返回值:
返回大于0或者等于0都表示读取成功,表示实际读到的字节数。
返回-1表示失败。

3 write往一个打开的文件中写入数据

NAME
write - write to a file descriptor

SYNOPSIS
#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);

参数列表:
fd: 文件描述符 ,表示你要往哪个打开的文件中写入数据。
buf: 指向一段内存空间 这段空间保存了你要写入到文件中的内容。
count:你要写入多少个字节的数据 。

返回值:
成功返回实际写入的字节数。
失败返回-1 。

4 close关闭一个文件

NAME
close - close a file descriptor

SYNOPSIS
#include <unistd.h>

​ int close(int fd);

参数列表:
fd: 文件描述符 ,表示你要关闭哪个文件。

返回值:

​ 成功返回0,失败返回-1,同时errno被设置。

5 lseek重新定位read/write光标的位置

NAME
lseek - reposition read/write file offset

SYNOPSIS
#include <sys/types.h>
#include <unistd.h>

​ off_t lseek(int fd, off_t offset, int whence);

函数参数:
fd:文件描述符,你要在哪个打开的文件中进行光标定位操作。
offset: 偏移量,具体光标定位的位置,需要配合第三个参数来确定
偏移量可正可负为正表示向后向右偏移; 为负表示向前向左偏移。
whence: 从哪儿开始。
SEEK_SET: 相当于文件开头开始偏移
SEEK_CUR: 相当于光标现在的开始偏移
SEEK_END:相当于文件末尾开始偏移
第二个参数和第三个参数一起决定了光标定位的位置 。
第二个参数确定移动的字节数,第三个参数确定光标的起点 。

返回值:
成功返回 ,新光标位置到文件开头的距离(字节数)。
失败返回-1 同时errno被设置。

6 umask设置一个文件在创建时候的掩码

NAME
umask - set file mode creation mask

SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>

​ mode_t umask(mode_t mask);

函数参数: 指定文件的掩码 ,mode_t是个八进制数

返回值: 返回上一个文件掩码
      umask设置的权限位中为1的bit ,你在创建这个文件的时候不能真正的将它设置!

      umaks: 0022
      000   010   010
    用户(r-w-x)   组用户   其它用户
也就意味着,你在创建文件的时候,即使在代码中给权限0666,但是系统有自己的文件掩码比如0022,那么指定组用户的写权限和其他用户的写权限将不能设置成功!在创建文件后,去系统下ls -l列出信息发现其权限其实是0644!而不是代码中给的0666。

 分析:我们在代码中给的权限是0666
  代码权限:110 110 110 (用户、组用户、其它用户均可读可写)
  umask掩码:000 010 010(组用户的写权限、其他用户的写权限将不能设置)

 实际权限0644:110 100 100

7 用来获取进程的当前工作目录的绝对路径

NAME
getcwd, getwd, get_current_dir_name - get current working directory
SYNOPSIS
#include <unistd.h>

7.1 (有bug)getwd

​ char *getwd(char *buf);
参数列表:
​ buf: 指向一段内存空间,用来保存获取到的绝对路径 。
返回值:
​ 返回当前工作路径的字符串的首地址

注意: getwd有一个巨大的bug, 在编译的时候会报警告。

在这里插入图片描述

这是因为getwd有越界的风险, 如果buf指向的空间不是足够大的。getwd就有可能会访问buf后面的内存空间, 这样就会造成内存的非法访问。

在这里插入图片描述

#include <stdio.h> 
#include <unistd.h>
#include <string.h>
int main() 
{
    char buf[128]={0};//用来保存绝对路径 
 	//char buf[5]={0};//用来保存绝对路径

    char *p = getwd(buf);//指针p指向得到的绝对路径首地址

    printf("buf=%s\n",buf);//通过buf打印绝对路径,这里buf相当于一个指向字符串首地址的指针,指向不变,是个指针常量
    printf("p  =%s\n",p);//通过指针p打印绝对路径

    for(int i =0;i<strlen(buf);i++)
    {
        printf("buf[%d]= %c--->addr is %p \n",i,buf[i],&buf[i]);
    }
    printf("p =  %p\n",&*p);//指针p绝对路径首地址,p=&buf[0],那么*P=buf[0],&*p=&buf[0];
}  

7.2 getcwd

为了解决上面这个bug,getcwd函数出现了。

​ char *getcwd(char *buf, size_t size);
参数列表:
​ buf :指向一段空间用来保存路径
​ size:用来指定数组最大能存多少个字节的数据
返回值:
​ 返回当前目录字符串的首地址
​ 失败返回NULL 并且errno被设置

getcwd和getwd功能差不多, 只不过多了size参数 。size参数用来指定buf指向的空间的最大长度,如果当前工作目录的绝对路径字符串长度 > size, 这个函数就会报错。

7.3 (GNU拓展)get_current_dir_name

get_current_dir_name也是用来获取当前工作目录的绝对路径的 。

​ char *get_current_dir_name(void);

返回值:
成功返回当前工作目录字符串的首地址
失败返回NULL 并且errno被设置

注:#define _GNU_SOURCE //由于这个函数是GNU拓展,需要加这个宏,不然会段错误

只不过,这个函数不需要你输入参数 ,他会在内部自动地malloc足够长的空间来保存当前工作目录的字符串 ,并且返回这个首地址。 为了防止“内存泄漏” ,调用者在使用完了之后, 要free掉这个空间。

#define _GNU_SOURCE //这个函数是GNU拓展,需要加这个宏

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

int main() 
{
    char * p = get_current_dir_name();
    if(p == NULL)
    {
        perror("get_current_dir_name error ");
        return -1;
    }
    printf("p=%s\n",p);
    free(p);
    return 0;
}

8 truncate把指定的文件截短到指定的长度

NAME
truncate, ftruncate - truncate a file to a specified length

SYNOPSIS
#include <unistd.h>
#include <sys/types.h>

​ int truncate(const char *path, off_t length);
​ int ftruncate(int fd, off_t length);

参数列表:
​ path: 你要截短的文件的路径名
​ fd: 你要截短的文件的文件描述符
​ length: 截短后的文件内容的长度 (字节)

​ length < 源文件长度 就是 “截短”
​ length > 源文件长度 就是"扩展",补’\0’即nul

在这里插入图片描述

9 unlink、rmdir、remove删除一个文件或者空目录

9.1 unlink()从文件系统中删除一个文件。

NAME
unlink, unlinkat - delete a name and possibly the file it refers to

SYNOPSIS
#include <unistd.h>

​ int unlink(const char *pathname);

参数:
pathname: 你要删除的文件的路径名

返回值:

​成功返回0,失败返回-1,同时errno被设置。

需要注意的是:

  • 如果被删除的名称是文件的最后一个链接,并且没有进程打开该文件,则删除该文件,并将其使用的空间用于重用。
  • 如果该名称是到文件的最后一个链接,但只要有任何进程仍然打开该文件,则该文件将保持存在,直到打开它的最后一个文件描述符
    被关闭。
  • 如果该名称引用了符号链接,则该链接将被删除。
  • 如果该名称引用了套接字、FIFO或设备,则该名称将被删除,但打开该对象的进程可以继续使用它。

9.2 rmdir()从文件系统只能删除一个空目录

NAME
rmdir - delete a directory

SYNOPSIS
#include <unistd.h>

​ int rmdir(const char *pathname);
参数:
​ pathname: 你要删除的空目录的路径名

返回值:

​ 成功返回0,失败返回-1,同时errno被设置。

9.3 remove()从文件系统中删除一个文件或者空目录,它对文件调用unlink(),对目录调用rmdir()。

NAME
remove - remove a file or directory
SYNOPSIS
#include <stdio.h>

​ int remove(const char *pathname);
参数:
​ pathname: 你要删除的普通文件或空目录的路径名

返回值:

​ 成功返回0,失败返回-1,同时errno被设置。

需要注意的是:

  • 如果被删除的名称是文件的最后一个链接,并且没有进程打开该文件,则删除该文件,并将其使用的空间用于重用。
  • 如果该名称是到文件的最后一个链接,但只要有任何进程仍然打开该文件,则该文件将保持存在,直到打开它的最后一个文件描述符
    被关闭。
  • 如果该名称引用了符号链接,则该链接将被删除。
  • 如果该名称引用了套接字、FIFO或设备,则该名称将被删除,但打开该对象的进程可以继续使用它。
    在这里插入图片描述
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

QJ敬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值