Tips:"分享是快乐的源泉💧,在我的博客里,不仅有知识的海洋🌊,还有满满的正能量加持💪,快来和我一起分享这份快乐吧😊!
喜欢我的博客的话,记得点个红心❤️和小关小注哦!您的支持是我创作的动力!数据源存放在我的资源下载区啦!
Linux程序开发(五):采用库函数方式编写文件操作
目录
1. 编程题
1.1. 编写类似ls命令的程序myls,能够实现在屏幕上显示目录下文件功能
要求:
- 如果直接运行
./myls,则打印当前目录下所有文件名称 - 如果运行
./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,能够实现一次性创建目录和文件功能
要求:
- 使用方法:
./createfiles <dirname> <文件数量> - 例如:
./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能够删除某个目录,以及目录下所有的文件
要求:
./myrmdir <dirname>- 如果目录下为空,就只删除目录
- 如果目录不为空就先删除目录下所有文件,再删除目录
- 假定
<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,实现目录拷贝功能
要求:
./cpdir <src_dir> <dest_dir>- 拷贝目录下所有文件
- 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,具备创建目录、复制目录、删除目录、更名目录、复制文件、删除文件、更名文件(先复制后删除)七大功能
要求:
- 创建目录:
./dowithfiles mkdir <dirname> - 复制目录:
./dowithfiles cpdir <src_dir> <dest_dir> - 删除目录:
./dowithfiles rmdir <dirname> - 更名目录:
./dowithfiles renamedir <dirname> - 复制文件:
./dowithfiles cp <filename> - 删除文件:
./dowithfiles rm <filename> - 更名文件:
./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

247

被折叠的 条评论
为什么被折叠?



