文件IO---------1.1系统IO

发布时间:2024年01月24日

目录

1.文件IO是什么?

2.Linux中具体的一些API函数接口(系统IO)

? ? 1.打开文件(open)

? ? ? ? ? ? ps(权限的指定方法):

? ? ? ? ? ? ? ? 1.使用OS定义的宏标识权限

? ? ? ? ? ? ? ? 2.直接使用八进制数字标识权限

? ? ? ? ? ? 函数返回值:

? ? ? ? ? ? ? ? 打开成功

? ? ? ? ? ? ? ? 打开失败 ? ??

? ? 2.关闭文件(close)

? ? 3.读写文件(read\write)

? ? ? ? 3.1write:把自己的数据放到文件里面去

? ? ? ? read:从文件中把数据拿出来

? ? 4.定位文件的光标(偏移量 lseek)

? ? 5.设置文件的掩码(umask)

? ? 6.获取和修改程序的当前工作路径

? ? ? ? 如何获取当前工作路径

????????修改当前的工作路径:

? ? 7.文件截短(truncate)

? ? 8.删除文件

? ? 9.获取文件的属性(stat)

? ? 10.目录操作

? ? ? ? 10.1目录和普通文件的区别

? ? ? ? 10.2目录操作的API函数

? ? ? ? ? ? a.打开目录(opendir)

? ? ? ? ? ? b.读取目录项(readdir)

? ? ? ? ? ? c.关闭目录(closedir)



1.文件IO是什么?

????????首先我们要了解IO的定义? ?IO:input ?output? ?指的是对文件的输入和输出操作的基本函数接口
? ??文件IO分为系统IO和标准IO

? ? Linux有一个设计思想:Everything is a file in Linux ?
? ? 这对对文件的操作接口是很重要的

? ? 文件系统:是用来存储,组织和管理文件的一套方法和规则

? ? 存储文件一般分为两个部分:
? ? ? ? 文件的属性:i-node唯一的标识一个文件的存在
? ? ? ? 文件本身的内容(用户数据)

? ? Linux中到底如何组织和存放文件的呢?? ? ?如图:
? ? ? ?
? ??
? ? 大概步骤:
? ? ? ? struct inode{}
? ? ? ? 用来描述一个文件的物理inode信息.系统识别到一个文件的存在,就会为它创建一个struct inode的结构体,一个文件只会唯一的对应一个struct inode

? ? ? ? 如果打开了某一个文件
? ? ? ? 使用struct file的结构体表示这个打开的文件

? ? ? ? 一个文件可以同时被多个进程打开,一个进程也可以同时打开多个文件
? ? ? ? 一个进程同时打开了多个文件,意味着需要保存每一个打开的文件的struct file
? ? ? ? 使用一个数组保存了所有struct file结构体的地址(结构体指针数组)

? ? ? ? 对于用户来说,我们操作文件的时候只需要知道数组的下标,就可以去操作这个文件,这个下标在用户的眼中,叫做文件描述符

? ? ? ? 操作文件的内部流程:
? ? ? ? ? ? 数字(文件描述符)
? ? ? ? ? ? ? ? ------->
? ? ? ? ? ? 进程文件表项的内容(结构体指针数组)
? ? ? ? ? ? ? ? ------->
? ? ? ? ? ? struct file?
? ? ? ? ? ? ? ? ------->
? ? ? ? ? ? struct inde?
? ? ? ? ? ? ? ? ------->
? ? ? ? ? ? 硬件上面的inode
? ? ? ? ? ? ? ? ------->
? ? ? ? ? ? 文件的本身的内容
? ? ? ? ?
? ? 为了方便,Linux把上面所有的流程都封装起来了,用户不需要知道具体的操作细节
? ? 只需要调用OS提供给我们的API函数接口就可以了

? ? Linux提供的这些用于操作文件的接口(如:open,read,write...)我们称之为系统IO
? ? 系统IO:操作系统提供给用户操作文件的接口!!!!

2.Linux中具体的一些API函数接口(系统IO)


? ? 注意:
? ? ? ? 系统IO提供的API函数接口有很多,在这里我们只提及其中一小部分(注重方法和基础的API)

? ? 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:要打开或者创建的文件的路径名(如果不写路径,默认就是程序的当前路径)
? ? ? ? ? ? ? ? 如: "/home/china/1.txt" ? or ?"1.txt"
? ? ? ? ? ? flags:打开文件的标记(使用位域实现,可以添加多个标记)
? ? ? ? ? ? ? ? O_RDWR ? ? ?read and write ? ? ?读写打开
? ? ? ? ? ? ? ? O_RDONLY ? ?read only ? ? ? ? ? 只读打开
? ? ? ? ? ? ? ? O_WRONLY ? ?write only ? ? ? ? ?只写打开
? ? ? ? ? ? ? ? 以上的三个标记只能选一个

? ? ? ? ? ? ? ? O_APPEND
? ? ? ? ? ? ? ? ? ? 追加标记,打开文件的时候,文件的偏移量(光标)在文件的末尾
? ? ? ? ? ? ? ? ? ? 默认情况下文件的偏移量在文件开头
? ? ? ? ? ? ? ? ? ? 偏移量可以看做是文件的光标(读和写的位置)

? ? ? ? ? ? ? ? O_CREAT
? ? ? ? ? ? ? ? ? ? 创建标记,如果文件不存在,则创建这个文件

? ? ? ? ? ? ? ? O_EXCL ?
? ? ? ? ? ? ? ? ? ? 和O_CREAT配合使用,用来测试文件是否存在
? ? ? ? ? ? ? ? ? ? 同时指定这两个标记,文件存在则会报错,并且errno被设置为EEXIST,文件不存在则创建
? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? O_TRUNC?
? ? ? ? ? ? ? ? ? ? truncate截短,在文件打开的时候,把文件的内容清空

? ? ? ? ? ? ? ? O_NONBLOCK
? ? ? ? ? ? ? ? ? ? 以非阻塞的方式打开文件,文件的默认打开方式是阻塞打开的
? ? ? ? ? ? ? ? ? ? 阻塞:等待
? ? ? ? ? ? ? ? ? ? ? ? 如果文件暂时没有内容可读,read这个文件就会等待(直到有数据可读)
? ? ? ? ? ? ? ? ? ? ? ? 如果文件暂时没有空间,write这个文件就会等待(直到有空间)
? ? ? ? ? ? ? ? ? ? 非阻塞:不等待
? ? ? ? ? ? ? ? ? ? ? ? 如果文件暂时没有内容可读,read这个文件就不会等待,直接返回一个错误
? ? ? ? ? ? ? ? ? ? ? ? 如果文件暂时没有空间,write这个文件不会等待,直接返回一个错误
? ? ? ? ? ? ? ? ....

? ? ? ? ? ? ? ? 多个标记可以使用 ?| ?连接
? ? ? ? ? ? ? ? (Linux中的标志大部分都是使用位域实现的,一个整数的某些bit有特殊的含义)

? ? ? ? ? ? ? ? O_RDWR | O_CREAT | O_TRUNC?
? ? ? ? ? ? ? ? 以读写的方式打开,文件不存在则创建,文件存在则清空内容

? ? ? ? ? ? ps(权限的指定方法):


? ? ? ? ? ? ? ? 指定文件的权限,当第二个参数中带有"O_CREAT"时,必须指定创建的文件的权限,有两种指定方式:


? ? ? ? ? ? ? ? 1.使用OS定义的宏标识权限
? ? ? ? ? ? ? ? ? ? S_IRWXU ?00700 ?user (file owner) has read, write, and execute permission
? ? ? ? ? ? ? ? ? ? S_IRUSR ?00400 user has read permission、
? ? ? ? ? ? ? ? ? ? S_IWUSR ?00200 user has write permission
? ? ? ? ? ? ? ? ? ? S_IXUSR ?00100 user has execute permission
? ? ? ? ? ? ? ? ? ? S_IRWXG ?00070 group has read, write, and execute permission
? ? ? ? ? ? ? ? ? ? S_IRGRP ?00040 group has read permission
? ? ? ? ? ? ? ? ? ? S_IWGRP ?00020 group has write permission
? ? ? ? ? ? ? ? ? ? S_IXGRP ?00010 group has execute permission
? ? ? ? ? ? ? ? ? ? S_IRWXO ?00007 others have read, write, and execute permission
? ? ? ? ? ? ? ? ? ? S_IROTH ?00004 others have read permission
? ? ? ? ? ? ? ? ? ? S_IWOTH ?00002 others have write permission
? ? ? ? ? ? ? ? ? ? S_IXOTH ?00001 others have execute permission

? ? ? ? ? ? ? ? ? ? U/USR ? 用户(文件的拥有者)
? ? ? ? ? ? ? ? ? ? G/GRP ? 组用户
? ? ? ? ? ? ? ? ? ? O/OTH ? 其他用户

? ? ? ? ? ? ? ? ? ? S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH?
? ? ? ? ? ? ? ? ? ? rw-r--r--
? ? ? ? ? ? ? ? ? ? 0644

? ? ? ? ? ? ? ? 2.直接使用八进制数字标识权限


? ? ? ? ? ? ? ? ? ? 0777
? ? ? ? ? ? ? ? ? ? ? ? 111 111 111
? ? ? ? ? ? ? ? ? ? ? ? rwx rwx rwx?
? ? ? ? ? ? ? ? ? ? 0664
? ? ? ? ? ? ? ? ? ? ? ? 110 110 100
? ? ? ? ? ? ? ? ? ? ? ? rw- rw- r--

? ? ? ? ? ? 函数返回值:

? ? ? ? ? ? ? ? 打开成功


? ? ? ? ? ? ? ? ? ? 返回打开的文件的文件描述符(进程文件表项的下标),是一个整数
? ? ? ? ? ? ? ? ? ? >2 ?&& ?int ?&& 未使用中的最小值
? ? ? ? ? ? ? ? ? ? 因为操作系统会为每一个进程打开三个文件
? ? ? ? ? ? ? ? ? ? ? ? 标准输入文件(键盘) ?文件描述符 ?STDIN_FILENO ? ?0
? ? ? ? ? ? ? ? ? ? ? ? 标准输出文件(终端) ?文件描述符 ?STDOUT_FILENO ? ?1
? ? ? ? ? ? ? ? ? ? ? ? 标准错误文件(终端) ?文件描述符 ?STDERR_FILENO ? ?2
? ? ? ? ? ? ? ? ? ? 后序操作这个文件的时候,就可以直接使用这个数字表示


? ? ? ? ? ? ? ? 打开失败 ? ??


? ? ? ? ? ? ? ? ? ? 返回-1,同时errno被设置 ?
? ? ? ? ? ? ? ? ? ? errno是一个全局变量,表示的是最后一次调用系统函数出错的错误码 ? ?
? ? ? ? ? ? ? ? ? ? NAME
? ? ? ? ? ? ? ? ? ? ? ? perror - print a system error message
? ? ? ? ? ? ? ? ? ? ? ? 打印系统的错误信息
? ? ? ? ? ? ? ? ? ? SYNOPSIS
? ? ? ? ? ? ? ? ? ? ? ? #include <stdio.h>
? ? ? ? ? ? ? ? ? ? ? ? void perror(const char *s);?
? ? ? ? ? ? ? ? ? ? ? ? perror可以把当前的错误码转化为对应的字符串并且打印出来
? ? ? ? ? ? ? ? ? ? ? ? perror("用户提示性字符串:");
? ? ? ? ? ? ? ? ? ? ? ? ======>
? ? ? ? ? ? ? ? ? ? ? ? 用户提示性字符串:errno转化之后的错误字符串

    ? ? ? ? ? ? int creat(const char *pathname, mode_t mode);
? ?     ? ? ? ? int openat(int dirfd, const char *pathname, int flags);
? ?     ? ? ? ? int openat(int dirfd, const char *pathname, int flags, mode_t mode);

? ? ?     ? ? ? open("/home/china/1.txt",O_RDWR);
? ? ?     ? ? ? ----->
? ? ?     ? ? ? dirfd = open("/home/china",I_RDONLY);
? ? ?     ? ? ? openat(dirfd,"1.txt",O_RDWR);

? ? 2.关闭文件(close)

? ? ? ? NAME
? ? ? ? close - close a file descriptor
? ? ? ? SYNOPSIS
? ? ? ? ? ? #include <unistd.h>
? ? ? ? ? ? int close(int fd);

? ? 3.读写文件(read\write)


? ? ? ? 3.1write:把自己的数据放到文件里面去


? ? ? ? NAME
? ? ? ? ? ? write - write to a file descriptor
? ? ? ? SYNOPSIS
? ? ? ? ? ? #include <unistd.h>?
? ? ? ? ? ? write的作用是把buf指针指向的内存的前面count个字节写入到fd表示的文件中去
? ? ? ? ? ? ssize_t write(int fd, const void *buf, size_t count);
? ? ? ? ? ? fd:你要把内容写入带哪一个文件中去(open的返回值)
? ? ? ? ? ? buf:指针,指向一段内存地址,存储了你要写入的数据
? ? ? ? ? ? ? ? 为什么要使用const呢?
? ? ? ? ? ? ? ? ? ? 从语义来说,在write函数的内部不应该通过buf去修改数据
? ? ? ? ? ? count:字节数量,表示你要写入多少个字节
? ? ? ? ? ? ? ? 返回值:
? ? ? ? ? ? ? ? ? ? >0 ?返回实际写入到文件中的数据(有可能小于count)
? ? ? ? ? ? ? ? ? ? =0 ?表示什么也没写入
? ? ? ? ? ? ? ? ? ? -1 ?表示写入失败,同时errno被设置
? ? ? ? ? ? ? ? ? ? 写入的位置位于文件的光标位置

    fd1=write(fd,buf,1024);
    if(fd1==-1)
    {
        perror("write 2.text");
        return -1;
    }    

? ? ? ? read:从文件中把数据拿出来


? ? ? ? NAME
? ? ? ? ? ? read - read from a file descriptor
? ? ? ? SYNOPSIS
? ? ? ? ? ? #include <unistd.h>
? ? ? ? ? ? read是从指定的文件中(fd)读取count个字节,存放到buf指向的内存空间中去
? ? ? ? ? ? ssize_t read(int fd, void *buf, size_t count); ? ? ? ?
? ? ? ? ? ? fd:你要从哪一个文件中读取内容(open的返回值)
? ? ? ? ? ? buf:指针,指向一段可用的内存空间,表示你要把读取到的数据存放到哪一个位置,不能是野指针,也不能是空指针
? ? ? ? ? ? count:字节数量,表示你要读取多少个字节
? ? ? ? ? ? ? ? 返回值:
? ? ? ? ? ? ? ? ? ? >0 ?返回实际读取到的数据数量(有可能小于count)
? ? ? ? ? ? ? ? ? ? =0 ?表示什么也没读到
? ? ? ? ? ? ? ? ? ? -1 ?表示读取失败,同时errno被设置
? ? ? ? ? ? ? ? ? ? 读取的位置位于文件的光标位置

? ? ? ? 注意:
? ? ? ? ? ? 文件的偏移量由内核自动维护,一般来说,打开文件的时候,offset=0
? ? ? ? ? ? 每一次成功的读和写都会让偏移量改变
? ? ? ? ? ? 你读/写了count个字节
? ? ? ? ? ? ? ? offset += count
? ? ? ? ? ? 在读写文件的时候,要注意文件的光标所在位置

    char buf[1024]={0};
    int fd1=read(fd,buf,1024);
    if(fd1==-1)
    {
        perror("read 1.text");
        return -1;
    }


? ? 4.定位文件的光标(偏移量 lseek)


? ? ? ? NAME
? ? ? ? ? ? lseek - reposition read/write file offset
? ? ? ? SYNOPSIS
? ? ? ? ? ? #include <sys/types.h>
? ? ? ? ? ? #include <unistd.h>
? ? ? ? ? ? 定位fd表示的文件的偏移量
? ? ? ? ? ? off_t lseek(int fd, off_t offset, int whence);
? ? ? ? ? ? fd:你要定位的文件的文件描述符
? ? ? ? ? ? offset:偏移量,具体的新位置需要结合第三个参数使用
? ? ? ? ? ? whence:定义标记,有三种
? ? ? ? ? ? ? ? SEEK_SET ? ? ? ?基于文件开头定位
? ? ? ? ? ? ? ? ? ? 新位置 = 文件开头 + offset(>=0)
? ? ? ? ? ? ? ? SEEK_CUR ? ? ? ?基于文件当前位置定位
? ? ? ? ? ? ? ? ? ? 新位置 = 文件当前光标位置 + offset(可正可负)
? ? ? ? ? ? ? ? SEEK_END ? ? ? ?基于文件结尾定位
? ? ? ? ? ? ? ? ? ? 新位置 = 文件结尾 + offset(可正可负)
? ? ? ? ? ? 如:
? ? ? ? ? ? ? ? 定位到文件开头
? ? ? ? ? ? ? ? lseek(fd,0,SEEK_SET);
? ? ? ? ? ? ? ? 定位到文件结尾
? ? ? ? ? ? ? ? lseek(fd,0,SEEK_END);
? ? ? ? 返回值:
? ? ? ? ? ? 成功返回新光标位置离文件开头的字节数量
? ? ? ? ? ? 失败返回-1,同时errno被设置

? ? ? ? 也可以利用lseek计算文件大小
? ? ? ? size = lseek(fd,0,SEEK_END);

? ? 5.设置文件的掩码(umask)


? ? ? ? umask ?表示创建文件时权限的掩码
? ? ? ? ? ? ? ? 创建文件时,不能指定umask中值为1的bit? ? ? ? umask ?------>0002 ? 000 000 010
? ? ? ? ? ? 在创建文件的时候,不能指定umask中值为1的bit(指定了也会忽略)
? ? ? ? ? ? mode = mode & (~umask)
? ? ? ? ? ? ? ? umask: 0002 ? ? 000 000 010
? ? ? ? ? ? ? ? mode: 0777 ? ? ?111 111 111
? ? ? ? ? ? ? ? &
? ? ? ? ? ? ? ? ~umask: 0002 ? ?111 111 101
? ? ? ? ? ? ? ? -------------------------------
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 111 111 101
? ? ? ? ? ? 默认情况下,组用户和其他用户的写权限是不能指定的(0022)
? ? ? ? ? ? 可以通过命令或者函数修改:

? ? ? ? ? ? 命令:
? ? ? ? ? ? ? ? umask + 新的掩码
? ? ? ? ? ? 函数:
? ? ? ? ? ? ? ? NAME
? ? ? ? ? ? ? ? ? ? umask - set file mode creation mask
? ? ? ? ? ? ? ? SYNOPSIS
? ? ? ? ? ? ? ? ? ? #include <sys/types.h>
? ? ? ? ? ? ? ? ? ? #include <sys/stat.h>

? ? ? ? ? ? ? ? ? ? mode_t umask(mode_t mask); ? ?
? ? ? ? ? ? ? ? ? ? ? ? mask:你要指定的新的文件掩码
? ? ? ? ? ? ? ? ? ? 返回值:
? ? ? ? ? ? ? ? ? ? 返回上一次的文件掩码

? ? 6.获取和修改程序的当前工作路径


? ? ? ? 在Linux中,任意一个程序都有一个工作路径
? ? ? ??
? ? ? ? 工作路径:在哪一个目录里面运行这个程序,这个程序的工作路径就在哪里(不管你的程序存储在哪一个位置)
? ? ? ? 如:
? ? ? ? 你有 /home/china/123/abc/a.out?
? ? ? ? 当前在: /home/china/123/abc 运行:a.out?
? ? ? ? ? ? 运行命令: ./a.out?
? ? ? ? ? ? 工作路径: /home/china/123/abc

? ? ? ? 当前在: /home/china ? 运行:a.out?
? ? ? ? ? ? 运行命令: ./123/abc/a.out
? ? ? ? ? ? 工作路径: /home/china
? ? ? ??
? ? ? ? 有什么意义呢?
? ? ? ? ? ? 你如果在a.out中写了
? ? ? ? ? ? ? ? int fd = open("1.txt", O_RDWR | O_CREAT ,0664);
? ? ? ? ? ? ? ? 这里的 "1.txt" 是相对路径,此相对路径是相对于工作路径而言的
? ? ? ? ? ? ? ? 如果你的工作路径是:/home/china/123/abc
? ? ? ? ? ? ? ? 就会去/home/china/123/abc找1.txt?

? ? ? ? ? ? ? ? 如果你的工作路径是:/home/china
? ? ? ? ? ? ? ? 就会去/home/china找1.txt?


? ? ? ? 如何获取当前工作路径


? ? ? ? NAME
? ? ? ? ? ? getcwd, getwd, get_current_dir_name - get current working directory
? ? ? ? SYNOPSIS
? ? ? ? ? ? #include <unistd.h>
? ? ? ? ? ? 把获取到的工作路径(绝对路径)保存到buf指向的内存空间(必须可用)
? ? ? ? ? ? char *getwd(char *buf);
? ? ? ? ? ? buf:是用来保存获取到的工作路径的
? ? ? ? ? ? 返回值:
? ? ? ? ? ? ? ? 成功返回获取到的工作路径字符串的首地址(buf)
? ? ? ? ? ? ? ? 失败返回NULL,同时errno被设置

? ? ? ? ? ? 警告: the `getwd' function is dangerous and should not be used.
? ? ? ? ? ? getwd有一个bug,不应该被使用,可能会造成内存越界
? ? ? ? ? ? 如果buf指向的空间不够大(当前目录字符串长度超出了buf指向的空间)
? ? ? ? ? ? getwd就会访问buf后面的空间(造成数据会误修改)

? ? ? ? ? ? getcwd是getwd的升级版本
? ? ? ? ? ? char *getcwd(char *buf, size_t size);
? ? ? ? ? ? buf:是用来保存获取到的工作路径的
? ? ? ? ? ? size:指定了buf可用空间的大小,如果当前的目录长度字符串超过了size-1,这个函数就会报错
? ? ? ? ? ? 返回值:
? ? ? ? ? ? ? ? 成功返回获取到的工作路径字符串的首地址(buf)
? ? ? ? ? ? ? ? 失败返回NULL,同时errno被设置 ? ?

? ? ? ? ? ? get_current_dir_name也是获取当前的工作路径,只不过这个函数不需要你给定空间,会在函数内部malloc自动分配足够长的空间,保存获取到的工作路径,并且返回首地址
? ? ? ? ? ? 所以为了防止内存泄漏,使用者使用完毕之后.应该free这个空间
? ? ? ? ? ? char *get_current_dir_name(void);
? ? ? ? ? ? 返回值:
? ? ? ? ? ? ? ? 成功返回获取到的工作路径字符串的首地址
? ? ? ? ? ? ? ? 失败返回NULL,同时errno被设置?? ? ? ?

????????修改当前的工作路径:
? ? ? ? ? ? 改变当前的工作路径
? ? ? ? ? ? NAME
? ? ? ? ? ? ? ? chdir, fchdir - change working directory
? ? ? ? ? ? SYNOPSIS
? ? ? ? ? ? ? ? #include <unistd.h>

? ? ? ? ? ? ? ? int chdir(const char *path);
? ? ? ? ? ? ? ? path:要切换到的工作路径的目录字符串
? ? ? ? ? ? ? ? chdir("/home/china/");

? ? ? ? ? ? ? ? int fchdir(int fd);
? ? ? ? ? ? ? ? int fd = open("/home/china/",O_RDONLY) ;
? ? ? ? ? ? ? ? fchdir(fd); ? ? ??
? ? ? ? ? ? 返回值:
? ? ? ? ? ? ? ? 成功会改变当前的工作路径,返回0
? ? ? ? ? ? ? ? 失败返回-1,同时errno被设置


? ? 7.文件截短(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);
? ? ? ? ? ? path: ? 你要截短的文件的路径名(相对路径/绝对路径)
? ? ? ? ? ? ? ? ? ? 绝对路径------>工作路径+path
? ? ? ? ? ? length: 截短之后的文件长度
? ? ? ? ? ? ? ? length < 原来的长度
? ? ? ? ? ? ? ? ? ? "截短":文件变成指定的长度
? ? ? ? ? ? ? ? length > 原来的长度?
? ? ? ? ? ? ? ? ? ? "留空洞"
? ? ? ? ? ? 返回值:
? ? ? ? ? ? ? ? 成功返回0
? ? ? ? ? ? ? ? 失败返回-1,同时errno被设置

? ? ? ? ? ? int ftruncate(int fd, off_t length);
? ? ? ? ? ? =====>
? ? ? ? ? ? int fd = open(...);
? ? ? ? ? ? ftruncate(fd,length);

? ? 8.删除文件


? ? ? ? rm 删除文件?
? ? ? ? rmdir 删除空目录

? ? ? ? unlink ?//删除一个普通文件
? ? ? ? rmdir ? //删除一个空目录
? ? ? ? remove ?//删除一个普通文件或者一个空目录

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

? ? ? ? SYNOPSIS
? ? ? ? ? ? #include <unistd.h>
? ? ? ? ? ? int unlink(const char *pathname);
? ? ? ? ? ? 删除一个文件的时候仅仅只是标记inode没有被使用了

? ? ? ? NAME
? ? ? ? ? ? rmdir - delete a directory

? ? ? ? SYNOPSIS
? ? ? ? ? ? #include <unistd.h>
? ? ? ? ? ? int rmdir(const char *pathname);
? ? ? ? ? ? 必须是空的

? ? ? ? NAME
? ? ? ? ? ? remove - remove a file or directory

? ? ? ? SYNOPSIS
? ? ? ? ? ? #include <stdio.h>

? ? ? ? ? ? int remove(const char *pathname);

ps.文件描述符是进程文件表项的下标(数组的下标),是大于0的整数
? ? ?系统IO是操作系统提供给用户操作文件的接口(一系列的API函数的统称)


? ? 9.获取文件的属性(stat)


? ? ? ? 任何一个文件都有自己的属性(inode中的内容)
? ? ? ? man -a inode?
? ? ? ? NAME
? ? ? ? ? ? stat, fstat, lstat, fstatat - get file status

? ? ? ? SYNOPSIS
? ? ? ? ? ? #include <sys/types.h>
? ? ? ? ? ? #include <sys/stat.h>
? ? ? ? ? ? #include <unistd.h>
? ? ? ? ? ? stat是用来获取pathname指定的文件的属性的,获取到的属性保存到statbuf指针指向的内存中
? ? ? ? ? ? int stat(const char *pathname, struct stat *statbuf);
? ? ? ? ? ? ? ? pathname:你要获取哪一个文件的属性(路径名)
? ? ? ? ? ? ? ? statbuf:指针,指向一块可用的空间,用来保存获取到的文件的属性的
? ? ? ? ? ? 返回值:
? ? ? ? ? ? ? ? 成功返回0,失败返回-1,同时errno被设置

? ? ? ? ? ? struct stat *statbuf = NULL;
? ? ? ? ? ? int r = stat("1.txt", statbuf); ?//ERROR
? ? ? ? ? ? ==============>
? ? ? ? ? ? struct stat statbuf; ?
? ? ? ? ? ? //struct stat *p = malloc(sizeof(*p));
? ? ? ? ? ? int r = stat("1.txt", &statbuf);
? ? ? ? ? ??

? ? ? ? ? ? fstat功能和stat类似,只不过需要提供文件描述符,需要提前打开文件
? ? ? ? ? ? int fstat(int fd, struct stat *statbuf);
? ? ? ? ? ? lstat功能和stat类似,只不过当pathname是一个符号链接的时候,lstat获取的是符号链接本身的属性信息(软连接同样有自己的inode)
? ? ? ? ? ? int lstat(const char *pathname, struct stat *statbuf);
? ? ? ? ? ? 文件B是文件A的符号链接(ln -s A B)
? ? ? ? ? ? B----->A?
? ? ? ? ? ? stat(B) ?获取的是A的inode的信息
? ? ? ? ? ? lstat(B) ?获取的是B的inode的信息? ? ? ? 文件的属性:


? ? ? ? ? ? 实际上Linux系统是使用一个结构体保存文件的所有属性信息

? ? ? ? ? ? struct stat {
? ? ? ? ? ? ? ?dev_t ? ? st_dev; ? ? ? ? /* ID of device containing file */
? ? ? ? ? ? ? ? ? ? //容纳该文件的设备的设备号码
? ? ? ? ? ? ? ?ino_t ? ? st_ino; ? ? ? ? /* Inode number */
? ? ? ? ? ? ? ? ? ? //inode号码
? ? ? ? ? ? ? ?mode_t ? ?st_mode; ? ? ? ?/* File type and mode */
? ? ? ? ? ? ? ? ? ? //保存了文件的权限和类型
? ? ? ? ? ? ? ?nlink_t ? st_nlink; ? ? ? /* Number of hard links */
? ? ? ? ? ? ? ? ? ? 硬链接数量
? ? ? ? ? ? ? ?uid_t ? ? st_uid; ? ? ? ? /* User ID of owner */
? ? ? ? ? ? ? ? ? ? 文件的所有者ID
? ? ? ? ? ? ? ?gid_t ? ? st_gid; ? ? ? ? /* Group ID of owner */
? ? ? ? ? ? ? ? ? ? 文件的组ID
? ? ? ? ? ? ? ?dev_t ? ? st_rdev; ? ? ? ?/* Device ID (if special file) */
? ? ? ? ? ? ? ? ? ? 如果文件是一个特殊的设备,设备号码
? ? ? ? ? ? ? ?off_t ? ? st_size; ? ? ? ?/* Total size, in bytes */
? ? ? ? ? ? ? ? ? ? 文件的大小(字节数量)
? ? ? ? ? ? ? ?blksize_t st_blksize; ? ? /* Block size for filesystem I/O */
? ? ? ? ? ? ? ?blkcnt_t ?st_blocks; ? ? ?/* Number of 512B blocks allocated */

? ? ? ? ? ? ? ?/* Since Linux 2.6, the kernel supports nanosecond
? ? ? ? ? ? ? ? ? precision for the following timestamp fields.
? ? ? ? ? ? ? ? ? For the details before Linux 2.6, see NOTES. */

? ? ? ? ? ? ? ?struct timespec st_atim; ?/* Time of last access */
? ? ? ? ? ? ? ? ? ? 最后访问时间
? ? ? ? ? ? ? ?struct timespec st_mtim; ?/* Time of last modification */
? ? ? ? ? ? ? ? ? ? 最后修改时间(修改了用户数据)
? ? ? ? ? ? ? ?struct timespec st_ctim; ?/* Time of last status change?
? ? ? ? ? ? ? ?*/ ? 最后修改时间 (修改了属性信息,inode中的内容)

? ? ? ? ? ? ? ? #define st_atime st_atim.tv_sec ? ? ?/* Backward compatibility */
? ? ? ? ? ? ? ? #define st_mtime st_mtim.tv_sec
? ? ? ? ? ? ? ? #define st_ctime st_ctim.tv_sec
? ? ? ? ? ?};


? ? ? ? 解析权限和类型的方式:

? ? ? ? mode_t ? ?st_mode; ? ? ? ?/* File type and mode */
? ? ? ? ? ? ? ? ? ? //保存了文件的权限和类型
? ? ? ? ? ? st_mode使用位域实现,可以使用以下的宏去解析这个变量
? ? ? ? ? ? 如:
? ? ? ? ? ? //获取文件的属性
? ? ? ? ? ? struct stat st; ?
? ? ? ? ? ? int r = stat("1.txt", &st);
? ? ? ? ? ? st.st_mode就保存了1.txt的文件的权限和类型
? ? ? ? ? ? 文件的类型
? ? ? ? ? ? ? ? S_IFMT ? ? 0170000 ? bit mask for the file type bit field

? ? ? ? ? ? ? ? S_IFSOCK ? 0140000 ? socket
? ? ? ? ? ? ? ? S_IFLNK ? ?0120000 ? symbolic link
? ? ? ? ? ? ? ? S_IFREG ? ?0100000 ? regular file
? ? ? ? ? ? ? ? S_IFBLK ? ?0060000 ? block device
? ? ? ? ? ? ? ? S_IFDIR ? ?0040000 ? directory
? ? ? ? ? ? ? ? S_IFCHR ? ?0020000 ? character device
? ? ? ? ? ? ? ? S_IFIFO ? ?0010000 ? FIFO

? ? ? ? ? ? ? ? to test for a regular file (for example)
? ? ? ? ? ? ? ? if ((st.st_mode & S_IFMT) == S_IFREG)?
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? //当前文件是一个普通文件
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? 或者:
? ? ? ? ? ? printf("File type: ? ? ? ? ? ? ? ?");
? ? ? ? ? ? switch (sb.st_mode & S_IFMT)?
? ? ? ? ? ? {
? ? ? ? ? ? case S_IFBLK: ?printf("block device\n"); ? ? ? ? ? ?break;
? ? ? ? ? ? case S_IFCHR: ?printf("character device\n"); ? ? ? ?break;
? ? ? ? ? ? case S_IFDIR: ?printf("directory\n"); ? ? ? ? ? ? ? break;
? ? ? ? ? ? case S_IFIFO: ?printf("FIFO/pipe\n"); ? ? ? ? ? ? ? break;
? ? ? ? ? ? case S_IFLNK: ?printf("symlink\n"); ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case S_IFREG: ?printf("regular file\n"); ? ? ? ? ? ?break;
? ? ? ? ? ? case S_IFSOCK: printf("socket\n"); ? ? ? ? ? ? ? ? ?break;
? ? ? ? ? ? default: ? ? ? printf("unknown?\n"); ? ? ? ? ? ? ? ?break;
? ? ? ? ? ? }
? ? ? ? ? ? ? ? 或者:
? ? ? ? ? ? S_ISREG(m) ?is it a regular file?
? ? ? ? ? ? S_ISDIR(m) ?directory?
? ? ? ? ? ? S_ISCHR(m) ?character device?
? ? ? ? ? ? S_ISBLK(m) ?block device?
? ? ? ? ? ? S_ISFIFO(m) FIFO (named pipe)?
? ? ? ? ? ? S_ISLNK(m) ?symbolic link? ?(Not in POSIX.1-1996.)
? ? ? ? ? ? S_ISSOCK(m) socket? ?(Not in POSIX.1-1996.)

? ? ? ? ? ? stat(pathname, &st);
? ? ? ? ? ? if (S_ISREG(st.st_mode))?
? ? ? ? ? ? {
? ? ? ? ? ? ? ? //当前文件是一个普通文件
? ? ? ? ? ? } ? ?

? ? ? ? ? ? 文件的权限
? ? ? ? ? ? printf("Mode: ?%lo (octal)\n",(unsigned long) st.st_mode); ? ?

? ? ? ? ? ? if(st.st_mode & S_IRUSR)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? //用户拥有可读的权限
? ? ? ? ? ? }else?
? ? ? ? ? ? {
? ? ? ? ? ? ? ? //用户,不拥有可读的权限
? ? ? ? ? ? }

? ? ? ?

????????但是不管你使用的是哪一个函数(stat/fstat/lstat)都是获取到上面结构体的信息
? ? ? ? 注意时间格式转化

? ? ? ? struct timespec?
? ? ? ? {
? ? ? ? ? ? time_t ? tv_sec; ? ? ? ?/* seconds */
? ? ? ? ? ? 秒,记录的是从1970年1月1日到现在的秒数
? ? ? ? ? ? long ? ? tv_nsec; ? ? ? /* nanoseconds */ ?//纳秒
? ? ? ? };
? ? ? ? ? ? 1s == 1000 ms?
? ? ? ? ? ? 1ms == 1000 us?
? ? ? ? ? ? 1us == 1000 ns?

? ? ? ? 既然你给出的是一个秒数,如何把一个秒数转化为时间呢?

? ? ? ? #include <time.h>

? ? ? ? time_t time(time_t *tloc); ?//获取本地时间秒数
? ? ? ? char *ctime(const time_t *timep); ? //把秒数转化为时间字符串
? ? ? ? ? ? timep:你要转化的秒数
? ? ? ? ? ? 可以把当前的秒数转化为一个表示时间的字符串
? ? ? ? ? ? 如:
? ? ? ? ? ? printf("%s\n",ctime(&st.st_atim.tv_sec));
? ? ? ? ? ? or?
? ? ? ? ? ? printf("%s\n",ctime(&st.st_atime));

? ? ? ? struct tm *localtime(const time_t *timep); ?


? ? ? ? ? ? 可以把一个当前的秒数转化为一个表示时间的结构体

? ? ? ? ? ? struct tm {
? ? ? ? ? ? ? ?int tm_sec; ? ?/* Seconds (0-60) */
? ? ? ? ? ? ? ?int tm_min; ? ?/* Minutes (0-59) */
? ? ? ? ? ? ? ?int tm_hour; ? /* Hours (0-23) */
? ? ? ? ? ? ? ?int tm_mday; ? /* Day of the month (1-31) */
? ? ? ? ? ? ? ?int tm_mon; ? ?/* Month (0-11) */
? ? ? ? ? ? ? ?int tm_year; ? /* Year - 1900 */
? ? ? ? ? ? ? ?int tm_wday; ? /* Day of the week (0-6, Sunday = 0) */
? ? ? ? ? ? ? ?int tm_yday; ? /* Day in the year (0-365, 1 Jan = 0) */
? ? ? ? ? ? ? ?int tm_isdst; ?/* Daylight saving time */
? ? ? ? ? ?};

? ? ? ? 如何获取系统时间:
? ? ? ? NAME
? ? ? ? ? ? time - get time in seconds
? ? ? ? SYNOPSIS
? ? ? ? ? ? #include <time.h>
? ? ? ? ? ? time_t time(time_t *tloc); ? ??
? ? ? ? ? ? =============================
? ? ? ? ? ? time_t tm = time(NULL);
? ? ? ? ? ? or?
? ? ? ? ? ? time_t tm;
? ? ? ? ? ? time(&tm);

? ? ? ? 如何获取更加精准的时间:
? ? ? ? NAME
? ? ? ? ? ? gettimeofday, settimeofday - get / set time

? ? ? ? SYNOPSIS
? ? ? ? ? ? #include <sys/time.h>


? ? ? ? ? ? //微秒级别的时间


? ? ? ? ? ? int gettimeofday(struct timeval *tv, struct timezone *tz);

? ? ? ? ? ? ? ? struct timeval {
? ? ? ? ? ? ? ? time_t ? ? ?tv_sec; ? ? /* seconds */
? ? ? ? ? ? ? ? suseconds_t tv_usec; ? ?/* microseconds */
? ? ? ? ? ? ? ? };


? ? ? ? ? ? //纳秒级别的时间


? ? ? ? ? ? int clock_gettime(clockid_t clk_id, struct timespec *tp);
? ? ? ? ? ? ? ? struct timespec?
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? time_t ? tv_sec; ? ? ? ?/* seconds */
? ? ? ? ? ? ? ? ? ? 秒,记录的是从1970年1月1日到现在的秒数
? ? ? ? ? ? ? ? ? ? long ? ? tv_nsec; ? ? ? /* nanoseconds */ ?//纳秒
? ? ? ? ? ? ? ? };
? ? ? ? 练习:
? ? ? ? ? ? 尝试使用上面的函数(获取文件的属性)

? ? 10.目录操作


? ? ? ? 目录在Linux中也是文件,我们能不能按照操作普通文件的方式去操作目录呢?
? ? ? ? ? ? 普通文件:
? ? ? ? ? ? ? ? 打开文件?
? ? ? ? ? ? ? ? 读写文件?
? ? ? ? ? ? ? ? 关闭文件?
? ? ? ? 如果可以,那么目录的内容是什么呢?

? ? ? ? 在Linux中,目录也是文件,也可以使用open打开(O_RDONLY)
? ? ? ? 也会返回一个文件描述符,但是我们使用read去读取内容的时候,会失败
? ? ? ? ? ? read failed: Is a directory
? ? ? ? 那么目录文件应该如何操作呢?


? ? ? ? 10.1目录和普通文件的区别


? ? ? ? ? ? 在Linux中,任何一个文件只要存在,就有自己的inode编号
? ? ? ? ? ? 目录文件也有自己的inode,同样保存了文件的属性信息(stat同样可以获取属性)
? ? ? ? ? ? 但是目录文件的内容和普通文件的内容有很大的差别
? ? ? ? ? ? 普通文件的内容就是用户记录的一些用户数据
? ? ? ? ? ? 目录文件的内容记录的文件和文件之间的组织关系,叫做"目录项"
? ? ? ? ? ? 可以理解为一个"二维表格",记录着当前目录下面的文件名和inode的对应关系

? ? ? ? ? ? 在创建一个空目录的时候,系统会自动的为目录预留一个"目录项数组"
? ? ? ? ? ? 把该目录下面的所有文件(第一层)都记录在这个"数组"中

? ? ? ? 10.2目录操作的API函数


? ? ? ? ? ? a.打开目录(opendir)


? ? ? ? ? ? ? ? NAME
? ? ? ? ? ? ? ? ? ? opendir, fdopendir - open a directory
? ? ? ? ? ? ? ? SYNOPSIS
? ? ? ? ? ? ? ? ? ? #include <sys/types.h>
? ? ? ? ? ? ? ? ? ? #include <dirent.h>

? ? ? ? ? ? ? ? ? ? DIR *opendir(const char *name);
? ? ? ? ? ? ? ? ? ? DIR *dir = opendir("/home/china");
? ? ? ? ? ? ? ? ? ? ========================
? ? ? ? ? ? ? ? ? ? DIR *fdopendir(int fd);
? ? ? ? ? ? ? ? ? ? int fd = open("/home/china",O_RDONLY);
? ? ? ? ? ? ? ? ? ? DIR *dir = fdopendir(fd);

? ? ? ? ? ? ? ? ? ? name/fd:你要打开的目录的路径名/文件描述符
? ? ? ? ? ? ? ? ? ? 返回值:
? ? ? ? ? ? ? ? ? ? 成功就会返回一个DIR指针(指向当前目录项的指针)
? ? ? ? ? ? ? ? ? ? 失败返回NULL,同时errno被设置
? ? ? ? ? ? ? ? 在Linux中,使用DIR结构体表示一个打开的目录,至于目录里面有什么,不需要关心,只需要知道DIR类型的指针表示一个已经打开的目录就可以了,后序操作这个目录的时候,使用这个指针表示这个目录即可

? ? ? ? ? ? b.读取目录项(readdir)


? ? ? ? ? ? ? ? 通过读取目录项,就可以知道目录中有哪些文件了
? ? ? ? ? ? ? ? NAME
? ? ? ? ? ? ? ? ? ? readdir - read a directory
? ? ? ? ? ? ? ? SYNOPSIS
? ? ? ? ? ? ? ? ? ? #include <dirent.h>

? ? ? ? ? ? ? ? ? ? readdir是用来从dirp指向的目录中,读取下一个"目录项"的指针,一个目录中有多少个"目录项",就有多少个文件

? ? ? ? ? ? ? ? ? ? 每一次调用readdir,都会给你返回一个指向目录项的指针,并且让指针指向下一个目录项(偏移量),直到返回NULL,表示读取完毕
? ? ? ? ? ? ? ? ? ? struct dirent *readdir(DIR *dirp);
? ? ? ? ? ? ? ? ? ? dirp:指向你要读取目录项的目录(是opendir的返回值)
? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? In ?the ?glibc ?implementation, ?the ?dirent ?structure ?isdefined as follows:

? ? struct dirent {
? ? ? ? ino_t ? ? ? ? ?d_ino; ? ? ? /* Inode number */
? ? ? ? ? ? 当前读取到的目录项的inode编号
? ? ? ? off_t ? ? ? ? ?d_off; ? ? ? /* Not an offset; see below */
? ? ? ? unsigned short d_reclen; ? ?/* Length of this record */
? ? ? ? unsigned char ?d_type; ? ? ?/* Type of file; not supported
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? by all filesystem types */
? ? ? ? ? ? //文件的类型?
? ? ? ? char ? ? ? ? ? d_name[256]; /* Null-terminated filename */
? ? ? ? ? ? //文件的名字?
? ? };
? ? ? ? ? ? ? ? 注意:
? ? ? ? ? ? ? ? 该结构体的成员,只有d_ino,和d_name两个成员是所有文件系统都支持的,如果你想要你的代码有更好的兼容性和可移植性,在代码中尽量只使用这两个成员

? ? ? ? ? ? ? ? 返回值:
? ? ? ? ? ? ? ?On ?success, readdir() returns a pointer to a dirent structure. ?(This structure may be statically allocated; do ?not attempt to free(3) it.)-------(这意味着它的空间不是在运行时分配的,例如堆栈或空闲存储内存,而是:它在可执行文件本身中,与字符串文字相比,区别在于写入字符串文字是未定义的行为。)

? ? ? ? ? ? ? ? ?If ?the ?end ?of ?the ?directory stream is reached, NULL is returned and errno is not changed. ??
? ? ? ? ? ? ? ? ?If ?an ?error ?occurs, NULL ?is ?returned and errno is set appropriately. ?

? ? ? ? ? ? c.关闭目录(closedir)


? ? ? ? ? ? ? ? NAME
? ? ? ? ? ? ? ? ? ? closedir - close a directory

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

? ? ? ? ? ? ? ? ? ? #include <dirent.h>

? ? ? ? ? ? ? ? ? ? int closedir(DIR *dirp);

文章来源:https://blog.csdn.net/zzzskkd/article/details/135756153
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。