Linux 系统IO函数

Linux系统IO函数

  1. int open(const char *pathname, int flags);
  2. int open(const char *pathname, int flags, mode_t mode);
  3. int close(int fd);
  4. ssize_t read(int fd, void *buf, size_t count);
  5. ssize_t write(int fd, const void *buf, size_t count);
  6. off_t lseek(int fd, off_t offset, int whence);
  7. int stat(const char *pathname, struct stat *statbuf);
  8. int lstat(const char *pathname, struct stat *statbuf);
open

在lesson9目录下,open.c使用函数1(上面列表的第一个),create.c使用函数2(上面列表的第二个)。

在这里插入图片描述

int open(const char *pathname, int flags, mode_t mode);//可变参数

​ 参数:

flags:对文件操作权限的设置和其他设置。flags参数是一个int类型的数据,占4个字节,32位

​ flags 32个位 每一位都是一个标志位

​ - 必选项:O_RDONLY, O_WRONLY, or O_RDWR. 三个操作互斥

​ These request opening the file read-only, write-only,or read/write

​ - 可选项:O_CREAT 文件不存在,创建新文件

mode:八进制的数,表示用户对新创建文件的操作权限,比如:0775

​ 最终的权限是:mode & ~umaskumask的作用是抹去某些权限

​ 返回值:

​ open(), openat(), and creat() return the new file descriptor,or -1 if an error occurred

create.c中的代码如下:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>
#include<unistd.h>

int main(){
    //创建一个新的文件
    int fd= open("create.txt",O_RDWR | O_CREAT,0777);
    if(fd==-1){
        perror("open");
    }
    //关闭
    close(fd);
    return 0;
}

需要注意的是函数2中的mode是一个八进制数,该数表示用户对新创建文件的操作权限,比如:0775,但最终的权限是由mode & ~umask决定的,umask的作用是抹去某些权限。在create.c的代码中,我们设置了mode是0777,但是对create.c编译运行之后产生的create.txt文件的操作权限如下:
在这里插入图片描述
操作权限为:rwx rwx r-x(111 111 101,即775),我们设置的mode为0777,但是实际文件的操作权限为0775,可见实际操作权限并不仅仅由我们设置的mode决定。

read&write

新建文件夹lesson10:
在这里插入图片描述
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);

  • 参数:
    • fd:文件描述符,通过文件描述符操作某个文件
    • buf:记录内存中存放数据的地方,是个数组的地址
    • count:指定的数组的大小
  • 返回值
    • 成功:
      • 0:返回实际读取到的字节数
      • =0:文件读取完了
    • 失败:-1,并且设置errorno

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

  • 参数:

    • fd:文件描述符,通过文件描述符操作某个文件

    • buf:要往磁盘写入的数据

      • count:要写的数据的实际大小
  • 返回值

    • 成功:返回实际读取到的字节数
    • 失败:-1,并且设置errorno

lesson10目录下有个大小为129772的英文txt文档,接下来使用read和write两个函数实现复制操作。
copyfile.c:

#include<stdio.h>
#include<unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(){
    //通过open打开english.txt文件
    /*
    查阅文档可知,需要导入三个头文件
        #include <sys/types.h>
        #include <sys/stat.h>
        #include <fcntl.h>
    */
   int srcfd=open("english.txt",O_RDONLY);
   if(srcfd==-1){
        perror("open");
        return -1;
   }
    //创建一个新文件
    int destfd=open("cpy.txt",O_WRONLY|O_CREAT,0664);
    if(destfd==-1){
        perror("open");
        return -1;
   }
    //频繁读写操作
    char buf[1024]={0};
    int len=read(srcfd,buf,sizeof(buf));
    //len>0表示文件中还有数据尚未被读取
    while((len=read(srcfd,buf,sizeof(buf)))>0){
        write(destfd,buf,len);
    }
    //关闭文件
    close(destfd);
    close(srcfd);

}

编译链接c文件获得可执行文件copy,并运行copy:
在这里插入图片描述

LseeK
   #include <stdio.h>
   int fseek(FILE *stream, long offset, int whence);//标准c库的函数
   #include <sys/types.h>
   #include <unistd.h>

   off_t lseek(int fd, off_t offset, int whence);//linux系统函数

    lseek()  repositions  the file offset of the open file description associated with the file descriptor fd to the argument offset according to the directive whence as follows:
  • 参数:

    • fd:文件描述符,通过文件描述符操作某个文件
    • offset:偏移量
    • whence:
      • SEEK_SET
        • 设置文件指针的偏移量
      • SEEK_CUR
        • 设置偏移量:当前位置+offset的值
      • SEEK_END
        • 设置偏移量:文件大小+offset的值
  • 返回值:返回文件指针的位置

  • 实例:

    • 移动文件指针到头文件:lseek(fd,0,SEEK_SET)
    • 获取当前文件指针的位置: lseek(fd,0,SEEK_CUR)
    • 获取文件长度:lseek(fd,0,SEEK_END)
    • 拓展文件长度:lseek(fd,100,SEEK_END)
      • 注意:需要写一次数据才能生效

    lesson11目录下有hello.txt和lseek.c两个文件,我们在lseek.c文件中对hello.txt的长度进行拓展。

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<unistd.h>

int main(){
    int fd=open("hello.txt",O_RDWR);
    if(fd==-1){
        perror("open");
        return -1;
    }
    //拓展文件长度
    int ret= lseek(fd,100,SEEK_END);
    if(ret==-1){
        perror("lseek");
        return -1;
    }
    //写入一个空数据(最好写入一个空数据,不然不能拓展文件长度)
    write(fd," ",1);
    //关闭文件
    close(fd);
    return 0;
}

编译链接lseek.c文件生成可执行文件并执行,可以看到hello.txt文件长度增加了101(使用NULL填充了100次,空格填充了一次)。
在这里插入图片描述
使用lseek拓展文件长度,可以用于下载任务。下载一个大小为2G的文件时,先使用lseek拓展出一个大小为2G的空间,再将下载的文件填充到该空间。

stat&lstat

创建目录lesson12

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

   int stat(const char *pathname, struct stat *statbuf);
   int lstat(const char *pathname, struct stat *statbuf);//用来获取软链接文件的信息

参数:

  • pathname:操作文件的路径
  • statbuf:结构体变量,传出参数,用于保存获取到的文件信息
  • 返回值:On success, zero is returned. On error, -1 is returned, and errno is set appropriately.

stat结构体:

struct stat { 

    dev_t st_dev; // 文件的设备编号 
    ino_t st_ino; // 节点 mode_t st_mode; // 文件的类型和存取的权限 
    mode_t st_mode; // 文件的类型和存取的权限
    nlink_t st_nlink; // 连到该文件的硬连接数目 
    uid_t st_uid; // 用户ID 
    gid_t st_gid; // 组ID 
    dev_t st_rdev; // 设备文件的设备编号 
    off_t st_size; // 文件字节数(文件大小) 
    blksize_t st_blksize; // 块大小 
    blkcnt_t st_blocks; // 块数 
    time_t st_atime; // 最后一次访问时间 
    time_t st_mtime; // 最后一次修改时间 
    time_t st_ctime; // 最后一次改变时间(指属性)

}

image-20221109145054108

S_IFMT八进制数值转为二进制为1111 0000 0000 0000 st_mode&S_IFMT判断文件类型

在lesson12中编写stat.c代码查看文件a.txt的内容:

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include<stdio.h>

int main(){
    struct stat statbuf;
    int ret=stat("a.txt",&statbuf);
    if(ret==-1){
        perror("stat");
        return -1;
    }

    printf("size: %ld\n",statbuf.st_size);
    return 0;
}

编译运行stat.c程序,运行结果如下:

image-20221109150827094

创建软连接文件b.txt 链接到a.txt文件

通过ll和stat命令查看b.txt的实际大小是5字节

在程序中stat查看b.txt获取的是a.txt的信息,lstat查看b.txt才获取到b.txt的信息

image-20221109151642464

模拟实现LS -L命令

ls -l命令能获取目录下所有文件的权限 修改时间等信息。

image-20221109152641327

ls-l.c代码如下:

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include<stdio.h>
#include<pwd.h>
#include<grp.h>
#include<time.h>
#include<string.h>
//模拟实现ls -l指令
//-rw-rw-r-- 1 ccb ccb    12 11月  9 15:04 a.txt
/*
    argc是参数数量,系统会根据传入的参数自动赋值
    一般输入有两个一个是可执行文件路径,一个是文件名称
*/
int main(int argc,char * argv[]){

    //判断输入的参数是否正确并给出提示
    if(argc<2){
        printf("%s filename\n",argv[0]);
        return -1;
    }
    //通过stat函数查看用户指定文件的信息
    struct stat st;
    int res= stat(argv[1],&st);
    if(res==-1){
        perror("stat");
        return -1;
    }

    //获取文件权限和文件类型
    char parms[11]={0};//用于保存“-rw-rw-r-- ”字符串 
    switch (st.st_mode&S_IFMT)
    {
    case S_IFLNK:
        parms[0]='l';//软链接
        break;
    case S_IFDIR:
        parms[0]='d';//目录
        break;
    case S_IFREG:
        parms[0]='-';//普通文件
        break;
    case S_IFBLK:
        parms[0]='b';//块设备
        break;
    case S_IFSOCK:
        parms[0]='s';//套接字
        break;
    case S_IFCHR:
        parms[0]='c';//字符文件
        break;
    case S_IFIFO:
        parms[0]='i';//管道文件
        break;
    default:
        parms[0]='?';
        break;
    }

    //判断文件访问权限
    //文件所有者
    parms[1]=(st.st_mode&S_IRUSR)?'r':'-';
    parms[2]=(st.st_mode&S_IWUSR)?'w':'-';
    parms[3]=(st.st_mode&S_IXUSR)?'x':'-';
    //文件所在组
    parms[4]=(st.st_mode&S_IRGRP)?'r':'-';
    parms[5]=(st.st_mode&S_IWGRP)?'w':'-';
    parms[6]=(st.st_mode&S_IXGRP)?'x':'-';
    //其他人
    parms[7]=(st.st_mode&S_IROTH)?'r':'-';
    parms[8]=(st.st_mode&S_IWOTH)?'w':'-';
    parms[9]=(st.st_mode&S_IXOTH)?'x':'-';    
    //硬链接数
    int linkNum=st.st_nlink;

    //文件所有者
    char * fileUser=getpwuid(st.st_uid)->pw_name;
    //文件所在组
    char * fileGroup=getgrgid(st.st_gid)->gr_name;
    //文件大小
    long int fileSize=st.st_size;
    //获得修改时间
    char * editTime=ctime(&st.st_mtime);
    char mtime[512]={0};
    strncpy(mtime,editTime,strlen(editTime)-1);//去掉editTime最后的换行符
    char buf[1024];
    sprintf(buf,"%s %d %s %s %ld %s %s",parms,linkNum,fileUser,fileGroup,fileSize,mtime,argv[1]);
    printf("%s\n",buf);
    return 0;
}

编译运行之后结果如下:

image-20221109172501368

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值