Linux编程学习笔记-Linux系统文件编程详解

Linux系统文件编程详解

    • Linux文件操作命令
      • ls命令
      • cp命令
      • mkdir命令
      • mv命令
      • cat命令
      • rm命令
      • grep命令
      • more命令
    • Linux文件系统
    • Linux文件编程
      • 打开文件
      • 关闭文件
      • 读取文件
      • 写入文件
      • 文件偏移量
      • 获取文件状态
      • 文件锁定
      • 内存映射

Linux文件操作命令

ls命令

  • 功能:列出指定目录下的内容及其相关属性信息

  • 语法:ls [参数选项] [文件]

  • 常见参数:

    -a 显示所有文件以及目录,包括'以"."开头的隐藏文件'
    -l 使用长格式列出文件及目录信息
    -r 将文件以相反次序显示(默认依英文字母次序)
    -t 根据最后的修改时间排序
    -A 显示所有文件以及目录,但不列出"."(当前目录)".."(父目录)
    -S 根据文件大小排序
    -R 递归列出所有子目录
  • 示例:

    # 列出文件详情
    coder@coder-vm:/$ ls -l
    # 列出当前工作目录下所有名称是"s"开头的文件,在ubuntu中还会将文件夹以及其中的文件信息
    coder@coder-vm:/$ ls -ltr s*
    # 列出指定目录下的详细信息包含子目录
    coder@coder-vm:/$ ls -lR /sys
    

cp命令

  • 功能:复制文件或目录

  • 语法:cp [参数选项] [文件1、文件2、…|文件夹] [目标地址]

  • 常见参数:

    -f 若目标文件已存在,则会直接覆盖原文件
    -i 若目标文件已存在,则会询问是否覆盖
    -p 保留源文件或目录的所有属性
    -r 递归复制文件和目录
    -d 当复制符号连接时,把目标文件或目录也建立为符号连接,并指向与源文件或目录连接的原始文件或目录
    -l 对源文件建立硬连接,而非复制文件
    -s 对源文件建立硬连接,而非复制文件
    -b 覆盖已存在的文件目标前将目标文件备份
    -v 详细显示cp命令执行的操作过程
    -a 等价于dpr选项
  • 示例:

    # 复制目录 -R 等价于 -r
    coder@coder-vm:~$ cp -R Code/ /Code_1/
    # 复制多个文件,Temp 要存在
    coder@coder-vm:~/Code$ cp -r CMakeLists.txt main.cpp ../Temp
    

mkdir命令

  • 功能:创建目录

  • 语法:mkdir [参数选项] [文件夹1、文件夹2、…]

  • 常见参数:

    -p 递归创建多级目录
    -m 建立目录的同时设置目录的权限
    -z 设置安全上下文
    -v 显示目录的创建过程
  • 示例:

    # 在指定位置创建文件夹
    coder@coder-vm:~$ mkdir dir
    # 递归创建文件夹
    coder@coder-vm:~$ mkdir -p dir/code/
    

mv命令

  • 功能:可以移动文件或对其改名

  • 语法:mv [参数选项] [源文件|源目录] [目标文件|目标目录]

  • 常见参数:

    -i 若存在同名文件,则向用户询问是否覆盖
    -f 覆盖已有文件时,不进行任何提示
    -b 当文件存在时,覆盖前为其创建一个备份
    -u 当源文件比目标文件新,或者目标文件不存在时,才执行移动此操作
  • 示例:

    # 文件重命名
    coder@coder-vm:~$ mv main.cpp hello.cpp
    # 剪切文件夹到指定目录下,指定目录提前创建
    coder@coder-vm:~$ mv Code/ Code_mv/
    

cat命令

  • 功能:查看文件内容

  • 语法:cat [参数选项] [文件]

  • 常见参数:

    -n 显示行数,空行也编号
    -s 显示行数,多个空行算一个编号
    -b 显示行数,空行不编号
    -E 每行结束处显示$符号
    -T 将TAB字符显示为^|符号
    -v 使用^M-引用,除了LFDTAB之外
    -e 等价于-vE组合
    -t 等价于-vT组合
    -A 等价于-vET组合
    –help 显示帮助信息
    –version 显示版本信息
  • 示例:

    # 查看文件内容和行号
    coder@coder-vm:~$ cat -n Code/CMakeLists.txt
    

rm命令

  • 功能:删除一个目录中的一个或多个文件或目录

  • 语法:rm [参数选项] [文件|文件夹]

  • 常见参数:

    -f 忽略不存在的文件,不会出现警告信息
    -i 删除前会询问用户是否操作
    -r/-R 递归删除
    -v 显示指令的详细执行过程
  • 示例:

    # 删除前逐一询问确认
    coder@coder-vm:~$ rm -i Code/CMakeLists.txt
    # 递归删除目录及目录下所有文件
    coder@coder-vm:~$ rm -rf Code/
    

grep命令

  • 功能:基于正则表达式的文本搜索

  • 语法:grep [参数选项]

  • 常见参数:

    -i 搜索时,忽略大小写
    -c 只输出匹配行的数量
    -l 只列出符合匹配的文件名,不列出具体的匹配行
    -n 列出所有的匹配行,显示行号
    -s 不显示不存在、没有匹配文本的错误信息
    -v 显示不包含匹配文本的所有行
    -w 匹配整词
    -x 匹配整行
    -r 递归搜索
    -q 禁止输出任何结果,已退出状态表示搜索是否成功
    -b 打印匹配行距文件头部的偏移量,以字节为单位
    -o 打印匹配行距文件头部的偏移量,以字节为单位
    -h 查询多文件时不显示文件名
  • 示例:

    # 多文件查询并支持使用通配符
    coder@coder-vm:~$ grep zwx file_* /etc/hosts
    file_1:zwx
    file_1:zwx
    file_1:zwxddkjflkdjfdlkfjlsdkj
    file_2:zwx
    file_4:dkfjlzwxejfkje
    file_4:zwx djfkdjf
    file_4:zwxedkfgj
    

more命令

  • 功能:用于将内容较长的文本文件内容进行分屏显示,并且支持在显示时定位关键字

  • 语法:grep [参数选项] [文件]

  • 常见参数:

    -num 指定每屏显示的行数
    -l more在通常情况下把^L当作特殊字符, 遇到这个字符就会暂停,-l选项可以阻止这种特性
    -f 计算实际的行数,而非自动换行的行数
    -p 先清除屏幕再显示文本文件的剩余内容
    -c -p相似,不滚屏,先显示内容再清除旧内容
    -s 多个空行压缩成一行显示
    -u 禁止下划线
    +/pattern 在每个文档显示前搜寻该字pattern,然后从该字串之后开始显示
    +num 从第num行开始显示
  • 内部命令

    Space键 显示文本的下一屏内容
    B键 显示文本的上一屏内容
    斜线符\ 向下n行,需要定义,默认为1行
    H键 显示帮助屏
    Enter键 向下n行,需要定义,默认为1行
    Q键 退出more命令
    = 输出当前的行号
    :f 输出文件名和当前的行号
    V 调用vi编辑器
    ! 调用Shell,并执行命令
  • 示例

    # 显示文件file的内容,显示之前先清屏,附已显示的百分比
    coder@coder-vm:~$ more -dc Code/CMakeLists.txt
    # 显示文件file的内容,每10行显示一次,而且在显示之前先清屏
    coder@coder-vm:~$ more -c -10 Code/CMakeLists.txt
    # 从第 20 行开始显示 file 之文档内容
    coder@coder-vm:~$ more +20 Code/CMakeLists.txt
    

Linux文件系统

在Linux中可以使用ls -l命令看到当前文件夹下全部文件或文件夹的属性信息:

coder@coder-vm:~/Code$ ls -l
-rw-rw-r-- 1 coder coder  110  116 09:50 CMakeLists_bk.txt

在每一个文件或者文件夹名称的前边详细描述了文件的信息,信息解析情况如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FcQfiG4M-1643122019252)(\image\文件属性信息解析.png)]

在Linux系统中内核为每一个新创建的文件分配一个i(索引 index node)节点。文件的属性信息就保存在索引节点里,访问文件时索引节点被复制到内存中,从而实现文件的快速访问。索引节点是Linux虚拟文件系统(Virtual File System VFS)的基本概念之一。

i节点不但包含某个文件属性信息,还包含指向存储文件数据的数据块的指针。在Linux中一个文件除了纯数据本身之外,还必须包含对这些纯数据的管理信息,这些管理信息称为元数据(mata data)保存在文件的i节点之中。因此,可以简单的将i节点看成一个结构体其中保存了一些文件信息:

  • 节点编号,每个i节点都有一个唯一的编号。
  • 文件类型。
  • 权限信息。
  • 文件的字节数。
  • 文件的拥有者uid。
  • 文件的所属组gid。
  • 文件的时间戳,i节点最近变动时间(ctime)内容最近变动时间(mtime)文件上次访问时间(atime)
  • 硬盘链接数。
  • 纯数据块的指针位置。

i节点的总数在格式化时给定,每个i节点大小一般为128字节或256字节,但实际是每1KB或2KB设置一个i节点,用df命令可以查看i节点总数已使用i节点数量,每次创建文件可用i节点就会减少1个,命令如下所示:

# 查看i节点信息
df -i
# 查看系统使用信息
df -h

在Linux中每个文件都有一个i节点号与之对应,可用通过命令查看某个文件的i节点号

coder@coder-vm:~/Code$ ls -i CMakeLists.txt 
1973171 CMakeLists.txt

这种i节点号虽然对应着具体文件,但i节点号不能被人所识别,人所能识别的就只有名称字符。因此,Linux系统中存在一个目录项概念,目录中包含了i节点号文件名对应关系,当用户打开文件时一共分为三个步骤:系统通过目录项找到这个文件名对应的i节点号通过i节点号获得节点信息根据节点信息找到文件块读取数据

Linux文件编程

在Linux中设备或者文件都是通过文件描述符进行,当打开或者创建一个文件的时候,内核像进程返回一个文件描述符(非负整数)并基于该文件描述符进行操作。

打开文件

  • 相关函数
#include 
int open(const char * pathname, int flags);
int open(const char * pathname, int flags, mode_t mode);
  • 参数说明
参数名称 说明
pathname 文件路径名称,相对路径绝对路径
flags 文件打开方式
mode 用来规定文件的所有者、文件的用户组及系统中其他用户的访问权限
  • flags标志说明
标志位 说明
O_RDONLY 打开一个只供读取文件(单选)
O_WRONLY 打开一个只供写入文件(单选)
O_RDWR 打开一个可供读写的文件(单选)
O_APPEND 数据写入时追加到文件末尾
O_CREAT 打开文件时如果不存在就创建文件
O_EXCL 在使用了O_CREAT字段情况下,文件存在文件打开失败
O_TRUNC 打开文件时将文件清空
O_DSYNC 每次写入时,等待数据写到磁盘上
O_RSYNC 每次读取时,等待相同部分先写到磁盘
O_SYNC 已同步方式写入文件,强制刷新缓冲到输出文件
  • mode标志说明
标志位 说明
S_IRUSR 文件所有者的读取权限位
S_IWUSR 文件所有者的写入权限位
S_IXUSR 文件所有者的执行权限位
S_IRWXU S_IRUSR|S_IWUSR|S_IXUSR
S_IRGRP 文件用户组的读取权限位
S_IWGRP 文件用户组的写入权限位
S_IXGRP 文件用户组的执行权限位
S_IRWXG S_IRGRP|S_IWGRP|S_IXGRP
S_IROTH 文件其他用户的读取权限位
S_IWOTH 文件其他用户的写入权限位
S_IXOTH 文件其他用户的执行权限位
S_IRWXO S_IROTH|S_IWOTH|S_IXOTH
  • 示例
#include 
#include 

using namespace std;
int main() {
    // 使用读写模式打开当前 exe 同级目录下的 test_data.txt
    int fd = open("./test_data.txt", O_RDWR);
    if (fd != -1) {
        cout << "test file open success." << endl;
    } else {
        cout << "test file open fail." << endl;
    }
    return 0;
}

关闭文件

文件不在使用的时候就要将其关闭,关闭后文件描述不再指向任何文件,如果不关闭文件将会造成系统文件描述符资源耗尽,此时,不可再次打开文件。因此,打开文件和关闭文件应成对使用,文件关闭时返回一个整数其中最常见的0表示关闭成功-1表示关闭失败

  • 相关函数
#include 
int close(int fd);
  • 参数说明
参数名称 说明
fd 文件创建或打开后或返回一个文件描述符是一个整型变量
  • 示例
#include 
#include 

using namespace std;
int main() {
    int fd = open("./test_data.txt", O_RDWR);

    if (fd != -1) {
        cout << "test file open success." << endl;
    } else {
        cout << "test file open fail." << endl;
        return -1;
    }
    close(fd);
    return 0;
}

读取文件

通过打开文件后返回文件描述符,可以读取文件中的数据,可以一次读取指定字节长度的内容到指定的缓存中,读取时返回值是实际读取的字节数,可通过目标读取字节实际读取字节的比较判断是否读取到文件的结尾。

  • 相关函数
#include 
ssize_t read(int fd, void * buf, size_t count);
  • 参数说明
参数名称 说明
fd 已经打开的文件描述符
buf 读取到的文件会存放到buf内存地址中
count 每次读取的文件数据的长度
  • 常见返回异常值
参数名称 说明
EINTR 此调用被信号所中断
EAGAIN 当使用不可阻断I/O时或无数据可读
EBADF 参数fd无效或者文件已经关闭
  • 示例
#include 
#include 
#include 

using namespace std;

int main() {
    int fd = open("./test_data.txt", O_RDWR);
	// ........
    size_t read_size = 1024;
    char read_buffer[1024];		// 读取数据缓存区
    while(true) {
        size_t read_real_size = read(fd, read_buffer, read_size);
        if (read_real_size > 0) {
            cout << "read size " << read_real_size << endl;
        } else {
            break;
        }
    }
    cout << "read over" << endl;
    close(fd);
    return 0;
}

写入文件

通过打开文件后返回文件描述符,可以向文件中的写入数据,可以将指定的缓存中的内容写入到文件中。

  • 相关函数
#include 
ssize_t write(int fd, const void * buf, size_t count);
  • 参数说明
参数名称 说明
fd 已经打开的文件描述符
buf 需要写入的数据的文件缓存
count 每次写入文件数据的长度
  • 常见返回异常值
参数名称 说明
EINTR 此调用被信号所中断
EADF 参数fd无效或者文件已经关闭
  • 示例
#include 
#include 
#include 
#include 

using namespace std;

int main() {
    int fd = open("./test_data.txt", O_RDWR);
    // ........
    char write_buffer[] = "hello";
    ssize_t write_size = write(fd, write_buffer, strlen(write_buffer));
    close(fd);
    return 0;
}

文件偏移量

文件可以直接从指定位置开始读写数据,文件偏移量指的是当前文件操作位置相对于目标位置的偏移,当打开一个文件时在未指定O_APPEND情况下默认是0,如果指定O_APPEND则文件偏移到文件的结尾与文件的长度相等。

  • 相关函数
#include 
off_t lseek(int fd, off_t offset, int whence);
  • 参数说明
参数名称 说明
fd 已经打开的文件描述符
offset 偏移的字节数该值与whence设置有关
whence 偏移量的计算位置标记
  • whence标志说明
标志位 说明
SEEK_SET offset为相对文件开始处的值
SEEK_CUR offset为相对当前位置处的值
SEEK_END offset为相对文件结尾处的值
  • 示例
#include 
#include 
#include 
#include 

using namespace std;
int main() {
    int fd = open("test_data.txt", O_RDWR);
    // 文件内容: hello seek file code
    off_t result = lseek(fd, 5, SEEK_SET);
    if (result == -1) {
        cout << "seek fail." << endl;
        return -1;
    }
    char buffer[] = "Insert";
    ssize_t w_result = write(fd, &buffer, strlen(buffer));
    close(fd);
    return 0;
}

获取文件状态

文件的状态信息包含了例如,文件所有者、文件修改时间、文件大小等

  • 相关函数
#include 
int stat(const char * path, struct stat * buf);
int fstat(int filedes, struct stat * buf);
int lstat(const char * path, struct stat * buf);
  • 参数说明
参数名称 说明
path 文件完整路径
filedes 文件描述符
buf stat结构体的指针

在三个函数中fstat需要一个已打开文件的描述符,即已经open过的文件,另外两个则是文件全路径。statlstat区别在于,当文件是一个符号链接时,前者返回链接指向文件的信息而后者返回链接文件的信息

  • stat结构体说明
变量类型 变量名称 变量说明
mode_t st_mode 文件对应的模式
ino_t st_ino inode节点号
dev_t st_dev 设备号码
dev_t st_rdev 特殊设备号码
nlink_t st_nlink 文件的链接数
uid_t st_uid 文件所有者
gid_t st_gid 文件所有者对应的组
off_t st_size 文件对应的字节数[普通文本]
time_t st_atime 文件最后被访问的时间
time_t st_mtime 文件内容最后被修改的时间
time_t st_ctime 文件状态改变的时间
blksize_t st_blksize 文件内容对应的块大小
blkcnt_t st_blocks 文件内容对应的块数量
  • 示例
#include 
#include 
#include 
#include 
#include 

using namespace std;

int main() {
    struct stat file_stat{};
    if (-1 == stat("test_data.txt", &file_stat)) {
        cout << "get stat fail." << endl;
        return -1;
    }
    // 文件长度
    cout << "文件长度 = " << file_stat.st_size << endl;
    // 文件节点号
    cout << "文件索引号 = " << file_stat.st_ino << endl;
    return 0;
}

文件锁定

可以通过给文件增加标记来避免共享的文件资源产生竞争状态,文件锁分为两种建议性锁强制性锁,前者只是给文件加上锁标识其他进程可以读取到该标识但不会真的阻止文件操作,后者则是在其他进程访问时组织相应的操作。

  • 相关函数
#include 
#include 
int fcntl(int fd, int cmd, struct flock * lock);
  • 参数说明
参数名称 说明
fd 文件描述符
cmd 操作的命令
lock 文件锁数据结构
  • cmd标志位说明
标志位 说明
F_GETLK 根据lock描述,决定是否上文件锁
F_SETLK 设置lock描述的文件锁
  • flock结构体说明
变量类型 变量名称 变量说明
short int l_type 锁定的状态
short int l_whence 决定l_start的计算起始位置
off_t l_start 锁定区域的开头位置
off_t l_len 锁定区域的大小,0表示锁到结尾
pid_t st_nlink 锁定动作的进程
  • whence标志位
标志位 说明
SEEK_SET l_start为相对文件开始处的值
SEEK_CUR l_start为相对当前位置处的值
SEEK_END l_start为相对文件结尾处的值

l_len表示加锁的长度,0为到文件末尾,l_pid表示操作文件的进程ID号。

  • 示例
#include 
#include 
#include 
#include 
#include 

using namespace std;
int main() {
    struct flock lock{};
    int fd = open("test_data.txt", O_RDWR);
    if (fd == -1) {
        return fd;
    }
    lock.l_type = F_WRLCK;      // 写入锁
    lock.l_whence = SEEK_SET;   // 文件的开始文件
    lock.l_start = 0;           // 相对于 l_whence 偏移量
    lock.l_len = 20;            // 锁20个字符
    lock.l_pid = getpid();
    /* 直接锁定文件 */
    int res = fcntl(fd, F_SETLK, &lock);
    cout << "文件上锁结果 : " << res << endl;

    close(fd);
    return 0;
}

内存映射

文件映射可以将普通文件映射到内存中,可以像访问内存一样对文件进行访问,不必再调用read或者write。

  • 相关函数
#include 
void * mmap(void * start, size_t length, int port, int flags, int fd, off_t offset);
  • 参数说明
参数名称 说明
start 映射区起始地址,通常为0,表示为系统默认
length 映射数据长度
port 表示映射区保护方式
flags 指定映射对象类型,组合值
fd 文件描述符
offset 被映射数据在文件中的起点
  • port类型说明
标志位 说明
PROT_EXEC 映射区可被执行
PROT_READ 映射区可读取
PROT_WRITE 映射区可写入
PROT_NONE 映射区不可访问
  • flags类型说明
标志位 说明
MAP_FIXED 固定映射地址,与start配套使用,一般不设置
MAP_SHARED 共享映射区域,映射区域允许其他进程共享,对区域写入数据会写入文件中
MAP_RIVATE 执行写入操作时会创建副本,不影响源文件
MAP_ANONYMOUS 匿名映射,不与文件关联,不与进程共享
MAP_DENYWRITE 禁止写入
MAP_LOCKED 映射区锁定
  • 示例
#include 
#include 
#include 
#include 
#include 

using namespace std;
int main() {
    char * mapped_mem, *p;

    // test_data.txt 
    // hello seek file code
	// hello lock file code
    int fd = open("test_data.txt", O_RDWR);
    int length = lseek(fd, 1, SEEK_END);
    lseek(fd, 0, SEEK_SET);
    mapped_mem = (char*) mmap(nullptr, length, PROT_WRITE | PROT_READ, MAP_PRIVATE, fd, 0);

    printf("%s\n", mapped_mem);

    /* 替换所以 hello -> write */
    char * hello_pos = nullptr;
    while ((hello_pos = strstr(mapped_mem, "hello"))) {
        memcpy(hello_pos, "write", 5);
        hello_pos += 5;
    }

    printf("%s\n", mapped_mem);

    close(fd);
    munmap(mapped_mem, length);

    return 0;
}

你可能感兴趣的:(Linux笔记,linux)