注:前言、目录见 https://blog.csdn.net/qq_44220418/article/details/108428971
友情提醒:仅供参考理解,请勿直接复制粘贴
友情提醒:仅供参考理解,请勿直接复制粘贴
友情提醒:仅供参考理解,请勿直接复制粘贴
文章目录
- 第一题
- 第二题
- 第三题
第一题
模拟Linux的
cp
命令
编写一个C语言程序,该程序产生的可执行文件名为cpx
,其功能类似于cp
命令。
当执行
cpx A B
(A
、B
为任意两个文件名)时,会将文件A
复制为文件B
cpx
后面没有跟文件名做参数,或是没有跟两个文件名,则报错
/** 思路:一边读一边写,模拟复制* */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>#define LEN 10005
#define RD_ONCE 100char error[LEN] = "";
char buf[RD_ONCE] = "";int main(int argc, char *argv[])
{// 如果没有传入的参数少于2个,则报错if (argc < 3){perror("错误:传入的参数个数少于2个");exit(1);}// 测试复制的目标文件是否存在if (access(argv[2], F_OK) != -1){sprintf(error, "错误:目标文件 %s 已存在", argv[2]);perror(error);exit(2);}// 打开文件int fd1 = open(argv[1], O_RDONLY);int fd2 = open(argv[2], O_RDWR | O_CREAT, 0755);if (fd1 == -1){sprintf(error, "错误:源文件 %s 打开失败", argv[1]);perror(error);exit(3);}if (fd2 == -1){sprintf(error, "错误:目标文件 %s 创建失败", argv[2]);perror(error);exit(4);}// 读取文件,同时写入while (read(fd1, buf, sizeof(buf) - 1)){write(fd2, buf, strlen(buf));// 每次操作完成使用memset函数把字符串清空// 避免读取字节数少于字符串容量时报错memset(buf, 0, RD_ONCE);}// 关闭文件close(fd1);close(fd2);return 0;
}
示例截图
第二题
编写C程序
sortx.c
,完成将一个无序的数据文件userdata.txt
递增(A
)或递减(D
)排序后输出到指定的磁盘文件中。
如:
\qquaduserdata.txt
内容为:34 -3 8 -12 6
\qquad 执行sortx D myorder.txt
后,myorder.txt
文件的内容为:34 8 6 -3 -12
/** 生成输入字符串后,思路同【作业003】第2、3题* */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>#define N 1000 // 假定文件总的输入的整数个数少于1000
#define I_N 10 // 假定文件总的输入的整数长度少于10
#define LEN 500 // 假定文件每个的输入的整数字符串长度少于500假定文件总的输入的整数长度少于10
#define ERR_LEN 500 // 假定文件每个的输入的整数字符串长度少于500char file_str[LEN]; // 文件读取的输入字符串int a[N]; // 存储整数的数组
int cnt = 0; // 存储输入整数的个数size_t len = 0; // 切割字符串长度参数
char *part; // 存储切割部分的字符串char num[N]; // 存储要每次写入的内容字符串char error[ERR_LEN] = ""; // 报错字符串// 比较函数1(用于降序排列)
int cmp1(const void*a, const void*b)
{return *(int*)(b)-*(int*)(a);
}// 比较函数2(用于升序排列)
int cmp2(const void*a, const void*b)
{return *(int*)(a)-*(int*)(b);
}int main(int argc, char *argv[])
{// 参数获取、判断if (argc < 3){perror("错误:参数个数少于2个");exit(1);}// 读取参数文件的数组字符串int fd1 = open("userdata.txt", O_RDONLY);if (fd1 == -1){perror("错误:文件 userdata.txt 打开失败");exit(2);}read(fd1, file_str, sizeof(file_str) - 1);close(fd1);// 用strsep函数切割C式字符串char* buff = file_str;while ((part = strsep(&buff, " ")) != NULL)a[cnt++] = atoi(part); // 用atoi函数将C式字符串转换为int并存入数组// 根据第一个参数A/D,用qsort函数降序排列if (strcmp(argv[1], "A") == 0)qsort(a, cnt, sizeof(int), cmp2);else if (strcmp(argv[1], "D") == 0)qsort(a, cnt, sizeof(int), cmp1);else{sprintf(error, "错误:排序选项参数 %s 有误", argv[1]);perror(error);exit(3);}// 将数组写入文件int fd = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0755);if (fd == -1){sprintf(error, "错误:文件 %s 打开失败", argv[2]);perror(error);exit(2);}for (int i = 0; i < cnt; ++i){int bytes = sprintf(num, "%d ", a[i]);write(fd, num, bytes);}write(fd, "\n", strlen("\n"));close(fd);return 0;
}
示例截图
第三题
编写C程序
listdir.c
,执行listdir sub1
完成将当前目录下子目录如sub1
中的所有文件名列出(列表字段为:权限码 文件名 长度)
/** 思路同【作业003】的第4题* 不过当时写的思路2直接切换工作目录并没有与考虑到目录不存在不会产生错误,现在已纠正*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>#define LEN 1000 // 假定路径字符串长度少于1000char path[LEN] = "";
char acc[11]; // 全局变量(堆区)存储函数 getAccess 要返回的字符串
const char acc_init[11] = "----------"; // 每次用acc_init初始化accchar error[LEN] = ""; // 错误字符串// 获取文件类型对应字符
char getType(__mode_t mode)
{if (S_ISDIR(mode)) return 'd';if (S_ISCHR(mode)) return 'c';if (S_ISBLK(mode)) return 'b';if (S_ISSOCK(mode)) return 's';if (S_ISFIFO(mode)) return 'p';if (S_ISLNK(mode)) return 'l';return '-';
}// 获取文件权限字符串
const char* getAccess(__mode_t mode)
{// 文件类型strcpy(acc, acc_init);acc[0] = getType(mode);// 文件权限// 判断用户权限if (mode & S_IRUSR) acc[1] = 'r';if (mode & S_IWUSR) acc[2] = 'w';if (mode & S_IXUSR) acc[3] = 'x';// 判断组权限if (mode & S_IRGRP) acc[4] = 'r';if (mode & S_IWGRP) acc[5] = 'w';if (mode & S_IXGRP) acc[6] = 'x';// 判断其他用户权限if (mode & S_IROTH) acc[7] = 'r';if (mode & S_IWOTH) acc[8] = 'w';if (mode & S_IXOTH) acc[9] = 'x';return acc;
}int main(int argc, char *argv[])
{// 如果没有传入参数,则默认选择当前目录if (argc < 2)strcpy(path, ".");elsestrcpy(path, argv[1]);// 判断目录是否存在if (access(path, F_OK) == -1){sprintf(error, "错误:目标目录 %s 不存在", path);perror(error);exit(1);}// 切换当前工作目录int res = chdir(path);// 打开指定目录DIR * dir_ptr = opendir(".");struct dirent * dir;if (dir_ptr == NULL){sprintf(error, "错误:目标目录 %s 打开失败", path);perror(error);exit(2);}// 读取每一个目录项,构造stat获取其属性struct stat buf;printf("%-20s%-30s%-30s\n", "access", "filename", "length(Byte)");printf("----------------------------------------------------------------------\n");while ((dir = readdir(dir_ptr)) != NULL){// 构造stat,读取文件属性int res = lstat(dir->d_name, &buf);if (res == -1){sprintf(error, "错误:读取目标文件 %s 的属性失败", dir->d_name);perror(error);exit(3);}printf("%-20s%-30s%-30ld\n", getAccess(buf.st_mode), dir->d_name, buf.st_size);}return 0;
}
示例截图