注:前言、目录见 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 100
char 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 // 假定文件每个的输入的整数字符串长度少于500
char 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 // 假定路径字符串长度少于1000
char path[LEN] = "";
char acc[11]; // 全局变量(堆区)存储函数 getAccess 要返回的字符串
const char acc_init[11] = "----------"; // 每次用acc_init初始化acc
char 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, ".");
else
strcpy(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;
}
示例截图