本节学习linux系统中常见的IO函数,讲解及其基本用法;

一、 open/close函数
open函数作用:系统调用open函数,打开指定路径的文件;
int open(const char *pathname, int flags);打开一个存在的文件;
int open(const char *pathname, int flags, mode_t mode);创建一个新的文件;
int open(const char *pathname, int flags, mode_t mode);
参数:
pathname:要创建(打开)文件的路径;
flags:对文件的操作权限和其他的设置
必选项: O_RDONLY, O_WRONLY, or O_RDWR.之间互斥;
可选项: O_CREAT 文件不存在会创建新文件;
mode:必须是一个8进制的数,表示创建新的文件的操作权限;例如:0775;
最终的权限是: the mode of the created file is (mode & ~umask).umask:0002;0775;
为什么是0777?rwx都为1,三组;
0777 111111111
0775 111111101
umask的作用:抹去某些权限。
返回值:返回一个新的文件描述符;如果失败则返回-1;
errno:属于linux系统函数库,库里面的一个全局变量,记录的是最近的错误号。
利用perror函数能够将errno错误的原因打印出来;
#include<stdio.h>
void perror(const char*s);作用:打印 errno对应的错误描述
s参数:用户描述,比如hello,最终打印的结果是 hello:XXX(实际错误的具体原因);
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <unistd.h>     
int main()
{
//创建一个新的文件,通过open调用;
   int fd= open("creat.txt",O_RDWR|O_CREAT,0777);
   if(fd==-1)
   {
        perror("open");
   }
   //关闭文件描述
    close(fd);
    return 0;
} 
close函数:关闭文件,传入的参数是一个文件描述符;
#include <unistd.h>
close(fd);
二、read/write函数
read函数:把文件的数据读到内存中;
write函数:把内存中的数据写到文件中;
利用read、write函数完成文件的复制;
read函数:
linux中对于read函数的介绍(man 2 read)
涉及的头文件:
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
参数:
fd:文件描述符,open得到的;通过文件描述符操作某个文件;
buf:需要读取数据存放的地方;数组的地址;传出参数;
count:指定的数组的大小;
返回值:
成功,返回
>0:返回实际的读取到的字节数;
=0:文件已经读取完成了;
失败:返回-1,并且设置errno,通过perror可以读取错误;
write函数
linux中对于read函数的介绍(man 2 write)
涉及的头文件:
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
参数: fd:文件描述符,open得到的;通过文件描述符操作某个文件;
buf:要往磁盘写入的数据;
count:要写的数据的实际大小;
返回值:
成功,实际写入的字节数;
失败:返回-1,设置errno;
实现功能:
现有一个english.txt文件,通过read函数读取TXT文件的值,再通过write函数将TXT文件中的值复制到一个新的文件中;
实现流程:
1、 通过open打开english.txt文件;2、 创建一个新的文件,拷贝文件;
3、 频繁的读写操作;
4、 关闭文件
#include <unistd.h>
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h> 
 #include <fcntl.h>
int main()
{
    int srcfd= open("english.txt", O_RDONLY);
    if(srcfd==-1)
    {
                perror("open");
                return -1;
    }
    //通过open打开english.txt文件;
    int  destfd = open("cpy.txt", O_WRONLY|O_CREAT,0664);
    if(destfd ==-1)
    {
                perror("open");
                return -1;
    }
    //创建一个新的文件,拷贝文件;
    char buf[1024]={0};
     int len= 0; 
     while((len=read(srcfd, buf, sizeof(buf)))>0)
     {
        write(destfd,buf,len);
     }
    //频繁的读写操作;
  
    close(destfd);
    close(srcfd);
    //关闭文件;
    return 0;
} 

三、lseek函数
lseek函数:主要用作文件指针的偏移;
read函数:
linux中对于lseek函数的介绍(man 2 lseek)
Linux系统函数
涉及的头文件:
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
参数:
fd:文件描述符,通过open得到,通过这个fd操作某个文件;
offset:偏移量;
whence:
SEEK_SET
设置文件指针的偏移量,从文件头开始偏移;
The file offset is set to offset bytes.
SEEK_CUR
设置偏移量;当前位置+第二个参数offset的值;
The file offset is set to its current location plus offset bytes.
SEEK_END
设置偏移量:文件的大小+第二个参数offset的值;
The file offset is set to the size of the file plus offset bytes.
返回值:返回文件指针的位置;
函数作用:
1、移动文件指针到头文件;lseek(fd,0, SEEK_SET);例如:文件反复从头文件开始读;
2、获取当前文件指针的位置:lseek(fd,0,SEEK_CUR);返回值:返回最终文件指针的位置;
3、获取文件长度lseek(fd,0,SEEK_END);从文件末尾偏移0个单位;
4、可以拓展文件的长度:当前文件10b,准备拓展为110b,增加了100个字节;
lseek(fd,100,SEEK_END);只进行了指针的移动,还需要写入一次才管用;
实现功能:
现有一个hello.txt文件,其为11个字节,现在通过lseek函数进行扩展,多余扩展100个字节;
实现流程:
1、 通过open打开hello.txt文件;2、 扩展文件长度
3、 写入一个空数据;
4、 关闭文件
      #include <unistd.h>
      #include <fcntl.h>
      #include <sys/types.h>
      #include <sys/stat.h>
      #include <stdio.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函数,只能将文件指针的位置进行后移,并不能进行文件的扩展,在文件指针后移的位置,写入一个字节,才能完成整个文件的扩展。
四、stat/lstat函数
stat函数:用于获取文件的相关信息;
lstat函数:获取软连接文件的相关信息;
linux 中对于是stat函数的说明:
Linux系统函数:
stat:
涉及的头文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
主要作用与参数:
//作用:获取一个文件相关的信息;返回文件相关的一个信息;
//参数:
pathname:操作文件的路径;获取哪个文件的信息呢?
statbuf:结构体变量,传出参数,用于保存获取到的信息;
st_mode变量:
返回值:
成功:返回0;
失败:返回-1;
通过errno打印错误原因;
int lstat(const char *pathname, struct stat *statbuf);
软连接文件。如果用stat获取软连接的文件,其实获取的是指向的文件的内容;
如果要获取软连接的文件就要用lstat;
实现功能:获取某个文件的相关文件信息;
现有一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
} 

五、模拟实现ls -l命令
如下图所示,我们经常使用ls -l指令对一个文件进行属性信息的查询;查询的内容主要包括:文件的类型和权限、文件所在的组、硬链接数、文件所有者、文件大小、文件修改的时间;
例如:下图中:-rw-rw-r-- 1 nowcoder nowcoder 12 4-р с 29 11:13 a.txt

我们本节所有实现的代码功能:即运行一个代码+文件名称,然后打印出ls-l命令所展示出来的信息:
//模拟实现ls -l指令
//-rw-rw-r-- 1 nowcoder nowcoder 12 4-р с 29 11:13 a.txt
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <string.h>
int main(int argc,char * argv[])
{
    //判断输入的参数是否正确,如果不正确,则给出提示;
    if(argc<2)
    {
        printf("%s filename\n",argv[0]);
        return -1;
    }
    //通过stat函数获取文件的信息
   struct stat st;
    int ret=stat(argv[1],&st);
    if(ret==-1)
    {
        perror("stat");
        return -1;
    }
//获取文件类型和文件权限
    char perms [11]={0};//用于保存文件类型和文件权限的字符数组;
    switch(st.st_mode & __S_IFMT)
    {
        case __S_IFLNK:
             perms[0]='l';
            break;
        case __S_IFDIR:
             perms[0]='d';
            break;
        case __S_IFREG:
             perms[0]='-';
            break;
        case __S_IFBLK:
             perms[0]='b';
            break;
        case __S_IFCHR:
             perms[0]='c';
            break;
        case __S_IFSOCK:
             perms[0]='s';
            break;
        case __S_IFIFO:
             perms[0]='p';
            break;
        default :
             perms[0]='?';
            break;
    }
    //判断文件的访问权限
    perms[1]=(st.st_mode & S_IRUSR )? 'r':'-';
    perms[2]=(st.st_mode & S_IWUSR )? 'w':'-';
    perms[3]=(st.st_mode & S_IXUSR )? 'x':'-';
    
    //判断文件所在组
    perms[4]=(st.st_mode & S_IRGRP )? 'r':'-';
    perms[5]=(st.st_mode & S_IWGRP )? 'w':'-';
    perms[6]=(st.st_mode & S_IXGRP )? 'x':'-';
     //其他人
    perms[7]=(st.st_mode & S_IROTH )? 'r':'-';
    perms[8]=(st.st_mode & S_IWOTH )? 'w':'-';
    perms[9]=(st.st_mode & S_IXOTH )? 'x':'-';
    //硬链接数
    int linknum = st.st_nlink;
    //文件所有者
   char * fileuser = getpwuid(st.st_uid)->pw_name; 
   //文件所在组
   char * groupuser = getgrgid(st.st_gid)->gr_name;
   //文件大小
   long int filesize = st.st_size;
   //获取修改的时间
   char * time = ctime(& st.st_mtime) ; 
   char  mtime[512]={0};
   strncpy(mtime,time,strlen(time)-1);
   char buf[1024];
   sprintf(buf,"%s %d %s %s %ld %s %s", perms,linknum,fileuser,groupuser,filesize,mtime,argv[1]);
   printf("%s\n",buf);
    return 0;
} 
其运行结果:

总结:本节介绍的是linux系统中常见的IO函数的介绍与使用;对基本功能、基本使用以及举例说明的方式对于IO函数做了讲解。
创作不易,还请大家多多点赞支持!!!



























