3、文件IO-常用函数解析

【二】文件IO

【查看目录:】

1、open():用于打开或创建一个文件。

2、close():用于关闭一个打开的文件。

3、read():用于从文件中读取数据。

4、write():用于向文件中写入数据。

5、lseek():用于移动文件读写位置。

6、opendir():用于打开一个目录流,用于后续的目录操作。

7、readdir():用于读取目录流中的下一个条目。

8、closedir():用于关闭目录流。

9、chmod():用于改变文件的权限。

10、stat():用于获取文件或目录的状态信息。

11、lstat():用于获取符号链接本身的状态信息(不跟随符号链接)。

12、静态库相关

13、动态库相关

1、open()

用于打开或创建一个文件

1.1函数原型

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

1.2参数

  • pathname:文件路径名。

  • flags:文件打开方式,如只读(O_RDONLY)、只写(O_WRONLY)、读写(O_RDWR)等。还可以包含文件创建标志(O_CREAT)、追加模式(O_APPEND)等。

  • mode:如果文件不存在且指定了 O_CREAT 标志,则按照该模式创建文件,如 0666(所有用户可读可写)。

1.3头文件

#include 

1.4示例

#include 
#include 
#include 
​
int main() {
    int fd = open("test.txt", O_RDWR | O_CREAT, 0666);
    if (fd == -1) {
        perror("open failed");
        return 1;
    }
    write(fd, "Hello, World!", 13);
    close(fd);
    return 0;
}

2、close()

关闭一个打开的文件

2.1函数原型

int close(int fd);

2.2参数

  • fd:文件描述符,即通过 open() 函数返回的文件标识。

2.3头文件

#include 

2.4示例

#include 
#include 
#include 
​
int main() {
    int fd = open("test.txt", O_RDONLY);
    if (fd == -1) {
        perror("open failed");
        return 1;
    }
    close(fd);
    printf("File closed successfully\n");
    return 0;
}

3、read()

从文件中读取数据

3.1函数原型

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

3.2参数

  • fd:文件描述符。

  • buf:存储读取数据的缓冲区。

  • count:要读取的字节数。

3.3头文件

#include 

3.4示例

#include 
#include 
#include 
​
int main() {
    int fd = open("test.txt", O_RDONLY);
    if (fd == -1) {
        perror("open failed");
        return 1;
    }
    char buf[1024];
    ssize_t bytes_read = read(fd, buf, 1024);
    if (bytes_read == -1) {
        perror("read failed");
        close(fd);
        return 1;
    }
    buf[bytes_read] = '\0';
    printf("Content: %s\n", buf);
    close(fd);
    return 0;
}

4、write()

向文件中写入数据

4.1函数原型

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

4.2参数

  • fd:文件描述符。

  • buf:要写入的数据缓冲区。

  • count:要写入的字节数。

4.3头文件

#include 

4.4示例

#include 
#include 
#include 
​
int main() {
    int fd = open("test.txt", O_WRONLY | O_CREAT, 0666);
    if (fd == -1) {
        perror("open failed");
        return 1;
    }
    ssize_t bytes_written = write(fd, "Hello, World!", 13);
    if (bytes_written == -1) {
        perror("write failed");
        close(fd);
        return 1;
    }
    printf("Bytes written: %zd\n", bytes_written);
    close(fd);
    return 0;
}

5、lseek()

移动文件读写位置

5.1函数原型

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

5.2参数

  • fd:文件描述符。

  • offset:偏移量,以字节为单位。

  • whence:偏移基准,可以是文件开头(SEEK_SET)、当前位置(SEEK_CUR)或文件末尾(SEEK_END)。

5.3头文件

#include 

5.4示例

#include 
#include 
#include 
​
int main() {
    int fd = open("test.txt", O_RDWR | O_CREAT, 0666);
    if (fd == -1) {
        perror("open failed");
        return 1;
    }
    write(fd, "Hello, World!", 13);
    off_t pos = lseek(fd, 0, SEEK_END);
    if (pos == -1) {
        perror("lseek failed");
        close(fd);
        return 1;
    }
    printf("File size: %ld bytes\n", pos);
    close(fd);
    return 0;
}

6、opendir()

打开一个目录流,用于后续的目录操作

6.1函数原型

DIR *opendir(const char *name);

6.2参数

  • name:目录路径。

6.3返回值

  • 成功时返回一个指向DIR结构体的指针,失败时返回NULL

6.4头文件

#include 

6.5示例

#include 
#include 
​
int main() {
    DIR *dir = opendir(".");
    if (dir == NULL) {
        perror("opendir failed");
        return 1;
    }
    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        printf("File: %s\n", entry->d_name);
    }
    closedir(dir);
    return 0;
}

7、readdir()

读取目录流中的下一个条目

7.1函数原型

struct dirent *readdir(DIR *dirp);

7.2参数

  • dirp:目录流指针,由opendir()返回。

7.3返回值

  • 成功时返回一个指向struct dirent结构体的指针,到达目录末尾或失败时返回NULL

7.4头文件

#include 

7.5示例

#include 
#include 
​
int main() {
    DIR *dir = opendir(".");
    if (dir == NULL) {
        perror("opendir failed");
        return 1;
    }
    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        printf("File: %s\n", entry->d_name);
    }
    closedir(dir);
    return 0;
}

8、closedir()

关闭目录流

8.1函数原型

int closedir(DIR *dirp);

8.2参数

  • dirp:目录流指针,由opendir()返回。

8.3返回值

  • 成功时返回0,失败时返回-1。

8.4头文件

#include 

8.5示例

#include 
#include 
​
int main() {
    DIR *dir = opendir(".");
    if (dir == NULL) {
        perror("opendir failed");
        return 1;
    }
    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        printf("File: %s\n", entry->d_name);
    }
    if (closedir(dir) == -1) {
        perror("closedir failed");
        return 1;
    }
    return 0;
}

9、chmod()

改变文件的权限

9.1函数原型

int chmod(const char *path, mode_t mode);

9.2参数

  • path:文件路径。

  • mode:新的权限模式。

9.3返回值

  • 成功时返回0,失败时返回-1。

9.4头文件

#include 

9.5示例

#include 
#include 
​
int main() {
    if (chmod("test.txt", 0644) == -1) {
        perror("chmod failed");
        return 1;
    }
    printf("File permissions changed successfully\n");
    return 0;
}

10、stat()

获取文件或目录的状态信息

10.1函数原型

int stat(const char *path, struct stat *buf);

10.2参数

  • path:文件或目录路径。

  • buf:用于存储状态信息的struct stat结构体的指针。用于存储文件或目录的状态信息。它包含了许多关于文件的详细信息,struct stat 的结构体定义通常如下:

struct stat {
    dev_t     st_dev;     // 文件所在的设备ID
    ino_t     st_ino;     // 文件的inode节点号
    mode_t    st_mode;    // 文件的类型和权限 【详情如下】
    nlink_t   st_nlink;   // 硬链接数
    uid_t     st_uid;     // 文件所有者的用户ID
    gid_t     st_gid;     // 文件所有者的组ID
    dev_t     st_rdev;    // 如果是特殊文件,设备ID
    off_t     st_size;    // 文件大小,以字节为单位
    blksize_t st_blksize; // 文件系统的块大小
    blkcnt_t  st_blocks;  // 文件占用的块数
    time_t    st_atime;   // 最后访问时间
    time_t    st_mtime;   // 最后修改时间
    time_t    st_ctime;   // 最后状态改变时间
};
  • st_mode:文件的类型和权限。

    • 文件类型可以通过以下宏来判断:

      • S_ISDIR(mode):是否是目录。

      • S_ISREG(mode):是否是普通文件。

      • S_ISLNK(mode):是否是符号链接。

      • S_ISCHR(mode):是否是字符设备。

      • S_ISBLK(mode):是否是块设备。

      • S_ISFIFO(mode):是否是命名管道(FIFO)。

      • S_ISSOCK(mode):是否是套接字。

    • 文件权限可以用以下宏来判断:

      • S_IRUSR:用户可读。

      • S_IWUSR:用户可写。

      • S_IXUSR:用户可执行。

      • S_IRGRP:组可读。

      • S_IWGRP:组可写。

      • S_IXGRP:组可执行。

      • S_IROTH:其他用户可读。

      • S_IWOTH:其他用户可写。

      • S_IXOTH:其他用户可执行。

10.3返回值

  • 成功时返回0,失败时返回-1。

10.4头文件

#include 
#include 

10.5示例 1

#include 
#include 
#include 
​
int main() {
    struct stat buf;
    if (stat("test.txt", &buf) == -1) {
        perror("stat failed");
        return 1;
    }
    printf("File size: %ld bytes\n", buf.st_size);
    printf("File type: ");
    if (S_ISREG(buf.st_mode)) {
        printf("Regular file\n");
    } else if (S_ISDIR(buf.st_mode)) {
        printf("Directory\n");
    } else {
        printf("Other type\n");
    }
    return 0;
}

10.6示例 2

#include 
#include 
#include 
#include 
​
int main() {
    struct stat buf;
    const char *filename = "test.txt";
if (stat(filename, &buf) == -1) {
    perror("stat failed");
    return 1;
}
​
printf("File: %s\n", filename);
printf("Size: %ld bytes\n", buf.st_size);
printf("Type: ");
if (S_ISDIR(buf.st_mode)) {
    printf("Directory\n");
} else if (S_ISREG(buf.st_mode)) {
    printf("Regular file\n");
} else if (S_ISLNK(buf.st_mode)) {
    printf("Symbolic link\n");
} else {
    printf("Other type\n");
}
printf("Permissions: ");
printf("%s", (buf.st_mode & S_IRUSR) ? "r" : "-");
printf("%s", (buf.st_mode & S_IWUSR) ? "w" : "-");
printf("%s", (buf.st_mode & S_IXUSR) ? "x" : "-");
printf("%s", (buf.st_mode & S_IRGRP) ? "r" : "-");
printf("%s", (buf.st_mode & S_IWGRP) ? "w" : "-");
printf("%s", (buf.st_mode & S_IXGRP) ? "x" : "-");
printf("%s", (buf.st_mode & S_IROTH) ? "r" : "-");
printf("%s", (buf.st_mode & S_IWOTH) ? "w" : "-");
printf("%s\n", (buf.st_mode & S_IXOTH) ? "x" : "-");
printf("Last access time: %s", ctime(&buf.st_atime));
printf("Last modification time: %s", ctime(&buf.st_mtime));
printf("Last status change time: %s", ctime(&buf.st_ctime));
​
return 0;
}

11、lstat()

获取符号链接本身的状态信息(不跟随符号链接)

11.1函数原型

int lstat(const char *path, struct stat *buf);

11.2参数

  • path:文件或目录路径。

  • buf:用于存储状态信息的struct stat结构体的指针。

11.3返回值

  • 成功时返回0,失败时返回-1。

11.4头文件

#include 
#include 

11.5示例

#include 
#include 
#include 
​
int main() {
    struct stat buf;
    if (lstat("symlink", &buf) == -1) {
        perror("lstat failed");
        return 1;
    }
    printf("Symbolic link points to: %s\n", buf.st_size);
    printf("File type: ");
    if (S_ISREG(buf.st_mode)) {
        printf("Regular file\n");
    } else if (S_ISDIR(buf.st_mode)) {
        printf("Directory\n");
    } else {
        printf("Other type\n");
    }
    return 0;
}

DIR *opendir(const char *name);

struct dirent *readdir(DIR *dirp);

int closedir(DIR *dirp);

int chmod(const char *path, mode_t mode);

int stat(const char *path, struct stat *buf);

int lstat(const char *path, struct stat *buf);

12、静态库

  • 文件后缀为 .a

  • 在编译时将代码直接链接到可执行文件中。

  • 优点:可执行文件独立运行,无需依赖外部库。

  • 缺点:可执行文件体积较大,更新库时需重新编译。

步骤:

1、编写库文件代码,编译为.o 目标文件。

2、 ar 命令 创建 libxxxx.a 文件 【 ar -rsv libxxxx.a xxxx.o】

3、链接静态库:【gcc -o 目标文件 源码.c -L路径 -lxxxx】 -L 表示库所在的路径 -l 后面跟库的名称

注: 静态库名字要以lib开头,后缀名为.a 。 没有main函数的.c 文件不能生成可执行文件。

12.1静态库示例

1. 编写库文件代码

假设我们有一个简单的数学运算库,包含加法和乘法功能。

文件结构:

mylib/
├── mathlib.h
├── add.c
└── mul.c

mathlib.h

// mathlib.h
int add(int a, int b);
int mul(int a, int b);

add.c

// add.c
#include "mathlib.h"
​
int add(int a, int b) {
    return a + b;
}

mul.c

// mul.c
#include "mathlib.h"
​
int mul(int a, int b) {
    return a * b;
}
2. 编译为 .o 目标文件
gcc -c add.c mul.c

这会生成 add.omul.o

3. 使用 ar 命令创建静态库
ar -rsv libmathlib.a add.o mul.o

这会生成一个静态库文件 libmathlib.a

4. 编写测试程序

main.c

// main.c
#include "mathlib.h"
#include 
​
int main() {
    printf("Addition: %d\n", add(5, 3)); // 输出 8
    printf("Multiplication: %d\n", mul(5, 3)); // 输出 15
    return 0;
}
5. 链接静态库并编译
gcc -o main main.c -L. -lmathlib
  • -L. 表示库文件在当前目录。

  • -lmathlib 表示链接的静态库名称为 libmathlib.a

6. 运行程序
./main

输出:

Addition: 8
Multiplication: 15

13、动态库

  • 文件后缀为 .so

  • 在运行时加载库文件。

  • 优点:可执行文件体积小,多个程序可共享同一份库文件。

  • 缺点:运行时需要确保库文件存在且路径正确。

步骤:

1、生成位置无关代码的目标文件【gcc -c -fPIC xxx.c xxxx.c ....】

2、生成动态库 【gcc -shared -o libxxxx.so xxx.o xxx.o ....】

3、编译可执行文件【gcc -o 目标文件 源码.c -L路径 -lxxxx】

注:执行动态库的可执行文件错误

./test: error while loading shared libraries: libmyheby.so: cannot open shared object file: No such file or directory 错误原因 :可执行文件所使用的动态库找不到

【解决办法】:

1、找到动态库,添加到/usr/lib里面(不建议)

2、使用【export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:你的动态库目录】(临时生效,新窗口都无效)

3、添加【export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:你的动态库目录】在~/.bashrc 文件里面 ,使用source ~/.bashrc 全部生效。

13.1动态库示例

1. 编写库文件代码

使用上述相同的 mathlib.hadd.cmul.c 文件。

2. 生成位置无关代码的目标文件
gcc -c -fPIC add.c mul.c

这会生成 add.omul.o

3. 生成动态库
gcc -shared -o libmathlib.so add.o mul.o

这会生成一个动态库文件 libmathlib.so

4. 编写测试程序

main.c

// main.c
#include "mathlib.h"
#include 
​
int main() {
    printf("Addition: %d\n", add(5, 3)); // 输出 8
    printf("Multiplication: %d\n", mul(5, 3)); // 输出 15
    return 0;
}
5. 编译可执行文件
gcc -o main main.c -L. -lmathlib
6. 解决动态库路径问题

运行程序时可能会提示动态库找不到,解决方法如下:

方法 1:临时设置环境变量

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
./main

方法 2:永久设置环境变量

echo 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.' >> ~/.bashrc
source ~/.bashrc
./main
7. 运行程序
./main

输出:

Addition: 8
Multiplication: 15
8. 查看可执行文件依赖的动态库
ldd main

这会列出 main 所依赖的所有动态库。

【有错请留言谢谢】

你可能感兴趣的:(LinuxC,算法,c++,linux)