Linux程序开发(五):采用库函数方式编写文件操作

Tips:"分享是快乐的源泉💧,在我的博客里,不仅有知识的海洋🌊,还有满满的正能量加持💪,快来和我一起分享这份快乐吧😊!

喜欢我的博客的话,记得点个红心❤️和小关小注哦!您的支持是我创作的动力!数据源存放在我的资源下载区啦!

Linux程序开发(五):采用库函数方式编写文件操作

1. 编程题

1.1. 编写类似ls命令的程序myls,能够实现在屏幕上显示目录下文件功能

要求:

  1. 如果直接运行./myls,则打印当前目录下所有文件名称
  2. 如果运行./myls <dirpath>,则打印path下所有文件名称

(1)编写C语言程序myls.c

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>     // 提供目录操作函数

int main(int argc, char *argv[]) {
    DIR *dirp;          // 定义目录指针
    struct dirent *dp;  // 定义目录项指针

    char *path;         // 存储路径名

    if (argc == 1) {
        path = ".";     // 如果没有传入目录路径,则默认为当前目录
    } else if (argc == 2) {
        path = argv[1]; // 如果有传入目录路径,则使用传入的路径
    } else {
        fprintf(stderr, "Usage: %s [dirpath]\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    dirp = opendir(path);   // 打开目录

    if (dirp == NULL) {
        perror("opendir");
        exit(EXIT_FAILURE);
    }

    while ((dp = readdir(dirp)) != NULL) {  // 循环读取目录项
        printf("%s\n", dp->d_name);         // 打印文件名称
    }

    closedir(dirp);     // 关闭目录

    return EXIT_SUCCESS;
}

(2)用gcc编译器进行程序编译

gcc -o myls myls.c

在这里插入图片描述

(3)运行程序

# 不输入路径,默认为当前目录
gcc ./myls

# 输入路径/目录
gcc ./myls /

1.2. 编写程序createfiles,能够实现一次性创建目录和文件功能

要求:

  1. 使用方法:./createfiles <dirname> <文件数量>
  2. 例如:./createfiles ddd 8

在这里插入图片描述
就是创建ddd目录,并在ddd目录下创建1.txt、2.txt一直到8.txt八个文件,文件内容可为空。

(1)编写C语言程序createfiles.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h> 

int main(int argc, char *argv[]) {
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <dirname> <file_count>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    char *dirname = argv[1];    // 目录名称
    int file_count = atoi(argv[2]);  // 文件数量

    if (mkdir(dirname, 0777) == -1) {
        perror("mkdir");   // 输出创建目录错误信息
        exit(EXIT_FAILURE);  // 退出程序
    }

    char filename[100];   // 存储文件名的数组

    for (int i = 1; i <= file_count; i++) {
        snprintf(filename, sizeof(filename), "%s/%d.txt", dirname, i);  // 构建文件名

        FILE *file = fopen(filename, "w");   // 打开文件
        if (file == NULL) {
            perror("fopen");    // 输出打开文件错误信息
            exit(EXIT_FAILURE);  // 退出程序
        }

        fclose(file);   // 关闭文件
    }

    printf("Directories and files created successfully.\n");  // 输出成功信息

    return EXIT_SUCCESS;
}

(2)用gcc编译器进行程序编译

gcc -std=c99 -o createfiles createfiles.c

# 因为刚刚使用gcc -o  createfiles createfiles.c进行编译的时候,出现了以下报错:
[root@node1 bc_2]# gcc -o createfiles createfiles.c 
createfiles.c: In function ‘main’:
createfiles.c:21:5: error: ‘for’ loop initial declarations are only allowed in C99 mode
     for (int i = 1; i <= file_count; i++) {
     ^
createfiles.c:21:5: note: use option -std=c99 or -std=gnu99 to compile your code


解决思路:这个错误提示是因为 C 语言标准中,在 for 循环的初始化表达式中声明变量是一个 C99 特性。如果使用旧的 C 标准编译代码,将会报告类似于 "for loop initial declarations are only allowed in C99 mode" 的错误。
解决这个问题的方法之一是,使用 -std=c99 或 -std=gnu99 编译选项来启用 C99 模式。

即: gcc -std=c99 -o createfiles createfiles.c

在这里插入图片描述

(3)运行程序

./createfiles  li-qi-liang   8

在这里插入图片描述

1.3. 编写程序myrmdir能够删除某个目录,以及目录下所有的文件

要求:

  1. ./myrmdir <dirname>
  2. 如果目录下为空,就只删除目录
  3. 如果目录不为空就先删除目录下所有文件,再删除目录
  4. 假定<dirname>下不存在其他正常目录

注意:由于Linux目录中总是存在”.“、”…“两个隐藏目录,所以在用readdir()函数判断是否为空时,得到的结果总是目录不为空。所以要排除这两个隐藏目录。

(1)编写c语言程序myrmdir

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>

// 递归删除目录及其下所有文件
void delete_dir(char *dirname);

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <dirname>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    char *dirname = argv[1];
    delete_dir(dirname);

    printf("Directory and files deleted successfully.\n");

    return EXIT_SUCCESS;
}

void delete_dir(char *dirname) {
    DIR *dir = opendir(dirname);
    if (dir == NULL) {
        perror("opendir");
        exit(EXIT_FAILURE);
    }

    struct dirent *entry;
    struct stat statbuf;

    while ((entry = readdir(dir)) != NULL) {
        // 排除 "."".." 目录
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }

        char filepath[1024];
        snprintf(filepath, sizeof(filepath), "%s/%s", dirname, entry->d_name);

        if (lstat(filepath, &statbuf) < 0) {
            perror("lstat");
            exit(EXIT_FAILURE);
        }

        if (S_ISDIR(statbuf.st_mode)) {
            // 如果是子目录,递归调用 delete_dir 函数删除子目录及其下所有文件
            delete_dir(filepath);
        } else {
            // 如果是文件,使用 unlink 函数删除文件
            if (unlink(filepath) < 0) {
                perror("unlink");
                exit(EXIT_FAILURE);
            }
        }
    }

    closedir(dir);

    // 删除当前目录
    if (rmdir(dirname) < 0) {
        perror("rmdir");
        exit(EXIT_FAILURE);
    }
}

(2)用gcc编译器进行程序编译

gcc -std=c99 -o myrmdir myrmdir.c

在这里插入图片描述

(3)运行程序

./myrmdir ./aaa

在这里插入图片描述

1.4. 编写程序cpdir,实现目录拷贝功能

要求:

  1. ./cpdir <src_dir> <dest_dir>
  2. 拷贝目录下所有文件
  3. dest_dir不存在,就新建;如存在就直接拷贝src_dir下所有文件到dir_dir中

(1)编写C语言程序cpdir

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>

// 拷贝文件
void copy_file(const char* src_path, const char* dest_path) {
    FILE* src_file = fopen(src_path, "rb"); // 以二进制只读方式打开源文件
    FILE* dest_file = fopen(dest_path, "wb"); // 以二进制写入方式创建/覆盖目标文件
    if (src_file == NULL || dest_file == NULL) {
        printf("无法打开文件\n");
        return;
    }

    int buffer_size = 4096;
    char* buffer = (char*)malloc(buffer_size); // 分配缓冲区内存
    if (buffer == NULL) {
        printf("内存分配失败\n");
        fclose(src_file);
        fclose(dest_file);
        return;
    }

    size_t bytes_read;
    while ((bytes_read = fread(buffer, 1, buffer_size, src_file)) > 0) {
        fwrite(buffer, 1, bytes_read, dest_file); // 将读取到的数据写入目标文件
    }

    free(buffer); // 释放缓冲区内存
    fclose(src_file);
    fclose(dest_file);
}

// 拷贝目录
void copy_directory(const char* src_dir, const char* dest_dir) {
    DIR* dir = opendir(src_dir); // 打开源目录
    if (dir == NULL) {
        printf("无法打开目录\n");
        return;
    }

    // 创建目标目录
    mkdir(dest_dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);

    struct dirent* entry;
    while ((entry = readdir(dir)) != NULL) { // 遍历源目录中每个文件/子目录
        if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
            char src_path[256];
            char dest_path[256];

            sprintf(src_path, "%s/%s", src_dir, entry->d_name); // 拼接源文件/子目录路径
            sprintf(dest_path, "%s/%s", dest_dir, entry->d_name); // 拼接目标文件/子目录路径

            struct stat file_stat; // 创建用于获取文件状态的结构体
            stat(src_path, &file_stat); // 获取源文件/子目录状态

            if (S_ISDIR(file_stat.st_mode)) {
                // 如果是子目录,递归地拷贝子目录
                copy_directory(src_path, dest_path);
            } else {
                // 如果是文件,拷贝文件
                copy_file(src_path, dest_path);
            }
        }
    }

    closedir(dir); // 关闭源目录
}

int main(int argc, char* argv[]) {
    if (argc < 3) {
        printf("用法:%s <src_dir> <dest_dir>\n", argv[0]);
        return 1;
    }

    const char* src_dir = argv[1]; // 源目录路径,从命令行参数获取
    const char* dest_dir = argv[2]; // 目标目录路径,从命令行参数获取

    copy_directory(src_dir, dest_dir); // 拷贝目录

    printf("目录拷贝完成\n");
    return 0;
}

(2)用gcc编译器进行程序编译

gcc -o cpdir cpdir.c

在这里插入图片描述

(3)运行程序

./cpdir

在这里插入图片描述

1.5. 采用库函数方式编写文件操作主程序dowithfiles,具备创建目录、复制目录、删除目录、更名目录、复制文件、删除文件、更名文件(先复制后删除)七大功能

要求:

  1. 创建目录:./dowithfiles mkdir <dirname>
  2. 复制目录:./dowithfiles cpdir <src_dir> <dest_dir>
  3. 删除目录:./dowithfiles rmdir <dirname>
  4. 更名目录:./dowithfiles renamedir <dirname>
  5. 复制文件:./dowithfiles cp <filename>
  6. 删除文件:./dowithfiles rm <filename>
  7. 更名文件:./dowithfiles rename <old_name> <new_name>

选做

(1)编写C语言程序dowithfiles

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>

// 创建目录
void create_directory(const char* dirname) {
    if (mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == -1) {
        printf("创建目录失败\n");
    } else {
        printf("成功创建目录\n");
    }
}

// 删除空目录
void delete_empty_directory(const char* dirname) {
    if (rmdir(dirname) == -1) {
        printf("删除目录失败\n");
    } else {
        printf("成功删除目录\n");
    }
}

// 递归删除目录及其子目录和文件
void delete_directory(const char* dirname) {
    DIR* dir = opendir(dirname);  // 打开目录
    if (dir == NULL) {
        printf("无法打开目录\n");  // 如果无法打开目录,则打印错误信息并返回
        return;
    }

    struct dirent* entry;  // 目录项结构体
    while ((entry = readdir(dir)) != NULL) {  // 读取目录中的每个目录项
        if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {  // 排除"."和".."目录项
            char path[256];
            sprintf(path, "%s/%s", dirname, entry->d_name);  // 构建当前目录项的完整路径

            struct stat file_stat;  // 文件状态结构体
            stat(path, &file_stat);  // 获取当前路径下文件的状态

            if (S_ISDIR(file_stat.st_mode)) {  // 判断是否为目录
                delete_directory(path);  // 递归调用删除目录函数,删除子目录
            } else {
                if (remove(path) == -1) {  // 删除非目录文件
                    printf("删除文件失败:%s\n", path);  // 如果删除文件失败,则打印错误信息
                } else {
                    printf("成功删除文件:%s\n", path);  // 如果成功删除文件,则打印成功信息
                }
            }
        }
    }

    closedir(dir);  // 关闭目录

    if (rmdir(dirname) == -1) {  // 删除空目录
        printf("删除目录失败:%s\n", dirname);  // 如果删除目录失败,则打印错误信息
    } else {
        printf("成功删除目录:%s\n", dirname);  // 如果成功删除目录,则打印成功信息
    }
}

// 递归复制目录及其子目录和文件
void copy_directory(const char* src_dir, const char* dest_dir) {
    DIR* dir = opendir(src_dir);  // 打开源目录
    if (dir == NULL) {
        printf("无法打开目录\n");  // 如果无法打开目录,则打印错误信息并返回
        return;
    }

    mkdir(dest_dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);  // 创建目标目录

    struct dirent* entry;  // 目录项结构体
    while ((entry = readdir(dir)) != NULL) {  // 读取源目录中的每个目录项
        if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {  // 排除"."和".."目录项
            char src_path[256];
            char dest_path[256];

            sprintf(src_path, "%s/%s", src_dir, entry->d_name);  // 构建源路径
            sprintf(dest_path, "%s/%s", dest_dir, entry->d_name);  // 构建目标路径

            struct stat file_stat;  // 文件状态结构体
            stat(src_path, &file_stat);  // 获取源路径下文件的状态

            if (S_ISDIR(file_stat.st_mode)) {  // 判断是否为目录
                copy_directory(src_path, dest_path);  // 递归调用复制目录函数,复制子目录
            } else {  // 文件复制
                FILE* src_file = fopen(src_path, "rb");  // 打开源文件(以二进制方式读取)
                FILE* dest_file = fopen(dest_path, "wb");  // 创建目标文件(以二进制方式写入)

                if (src_file == NULL || dest_file == NULL) {  // 检查文件打开是否成功
                    printf("无法打开文件\n");

                    if (src_file != NULL) {
                        fclose(src_file);
                    }

                    if (dest_file != NULL) {
                        fclose(dest_file);
                    }

                    return;
                }

                int buffer_size = 4096;  // 缓冲区大小
                char* buffer = (char*)malloc(buffer_size);  // 分配缓冲区内存

                if (buffer == NULL) {  // 检查内存分配是否成功
                    printf("内存分配失败\n");
                    fclose(src_file);
                    fclose(dest_file);
                    return;
                }

                size_t bytes_read;
                while ((bytes_read = fread(buffer, 1, buffer_size, src_file)) > 0) {  // 从源文件读取数据并写入目标文件
                    fwrite(buffer, 1, bytes_read, dest_file);
                }

                free(buffer);  // 释放缓冲区内存
                fclose(src_file);  // 关闭源文件
                fclose(dest_file);  // 关闭目标文件

                printf("成功复制文件:%s\n", src_path);  // 打印成功信息
            }
        }
    }

    closedir(dir);  // 关闭源目录
}

// 复制文件
void copy_file(const char* src_path, const char* dest_path) {
    FILE* src_file = fopen(src_path, "rb");  // 以二进制方式读取源文件
    FILE* dest_file = fopen(dest_path, "wb");  // 以二进制方式写入目标文件

    if (src_file == NULL || dest_file == NULL) {  // 检查文件打开是否成功
        printf("无法打开文件\n");

        if (src_file != NULL) {  // 如果源文件打开成功,则关闭源文件
            fclose(src_file);
        }

        if (dest_file != NULL) {  // 如果目标文件打开成功,则关闭目标文件
            fclose(dest_file);
        }

        return;
    }

    int buffer_size = 4096;  // 缓冲区大小
    char* buffer = (char*)malloc(buffer_size);  // 分配缓冲区内存

    if (buffer == NULL) {  // 检查内存分配是否成功
        printf("内存分配失败\n");
        fclose(src_file);
        fclose(dest_file);
        return;
    }

    size_t bytes_read;
    while ((bytes_read = fread(buffer, 1, buffer_size, src_file)) > 0) {  // 从源文件读取数据并写入目标文件
        fwrite(buffer, 1, bytes_read, dest_file);
    }
    
    free(buffer);  // 释放缓冲区内存
    fclose(src_file);  // 关闭源文件
    fclose(dest_file);  // 关闭目标文件

    printf("成功复制文件:%s\n", src_path);  // 打印成功信息
}


// 重命名或移动文件
void rename_file(const char* old_name, const char* new_name) {
    if (rename(old_name, new_name) == -1) {
        printf("重命名失败\n");
    } else {
        printf("成功重命名\n");
    }
}

int main(int argc, char* argv[]) {
    // 检查命令行参数数量,如果数量不符合要求,则打印用法信息并返回
    if (argc < 3) {
        printf("用法:\n"
               "./dowithfiles mkdir <dirname>\n"
               "./dowithfiles cpdir <src_dir> <dest_dir>\n"
               "./dowithfiles rmdir <dirname>\n"
               "./dowithfiles renamedir <dirname>\n"
               "./dowithfiles cp <src_file> <dest_file>\n"
               "./dowithfiles rm <filename>\n"
               "./dowithfiles rename <old_name> <new_name>\n");

        return 1;
    }

    // 根据命令执行相应的操作
    if (strcmp(argv[1], "mkdir") == 0 && argc == 3) {
        create_directory(argv[2]);  // 创建目录
    } else if (strcmp(argv[1], "cpdir") == 0 && argc == 4) {
        copy_directory(argv[2], argv[3]);  // 复制目录
    } else if (strcmp(argv[1], "rmdir") == 0 && argc == 3) {
        printf("确定要删除目录吗?(y/n) ");
        char c = getchar();

        if (c == 'y' || c == 'Y') {
            delete_directory(argv[2]);  // 删除目录
        } else {
            printf("取消删除目录\n");
        }
    } else if (strcmp(argv[1], "renamedir") == 0 && argc == 4) {
        rename_file(argv[2], argv[3]);  // 重命名目录
    } else if (strcmp(argv[1], "cp") == 0 && argc == 4) {
        copy_file(argv[2], argv[3]);  // 复制文件
    } else if (strcmp(argv[1], "rm") == 0 && argc == 3) {
        printf("确定要删除文件吗?(y/n) ");
        char c = getchar();

        if (c == 'y' || c == 'Y') {
            if (remove(argv[2]) == -1) {
                printf("删除文件失败\n");
            } else {
                printf("成功删除文件\n");
            }
        } else {
            printf("取消删除文件\n");
        }
    } else if (strcmp(argv[1], "rename") == 0 && argc == 4) {
        rename_file(argv[2], argv[3]);  // 重命名文件
    } else {
        printf("无效的命令或参数\n");
        return 1;
    }

    return 0;
}

(2)用gcc编译器进行程序编译

gcc -o dowithfiles dowithfiles.c

在这里插入图片描述

(3)运行程序,创建目录

./dowithfiles mkdir testdir

在这里插入图片描述

(4)运行程序,复制目录

./dowithfiles cpdir testdir newdir

在这里插入图片描述

(5)运行程序,删除目录

./dowithfiles rmdir testdir

在这里插入图片描述

(6)运行程序,重命名目录

./dowithfiles renamedir newdir
# 终端输入新的目录名。

在这里插入图片描述

(7)运行程序,复制文件

./dowithfiles cp testfile.txt destfile.txt

在这里插入图片描述

(8)运行程序,删除文件

./dowithfiles rm testfile.txt

在这里插入图片描述

(9)运行程序,重命名文件

./dowithfiles rename destfile.txt newfile.txt

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卡林神不是猫

如果您觉得有帮助可以鼓励小卡哦

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值