注:前言、目录见 https://blog.csdn.net/qq_44220418/article/details/108428971
友情提醒:仅供参考理解,请勿直接复制粘贴
友情提醒:仅供参考理解,请勿直接复制粘贴
友情提醒:仅供参考理解,请勿直接复制粘贴
第一题
简述Linux文件系统中的目录和inode节点在文件访问中的作用?硬链接和软链接有何区别?
目录文件中存储了该目录下的文件的索引信息。如果想要找到某个文件,首先需要找到这个文件所在目录的目录文件。
文件的主要属性信息都存放在inode节点中,Linux用inode号来识别不同的文件。
一个文件和另一个文件指向同一个inode节点,则称之为硬链接;一个文件的内容存储的是另一个文件的路径,则称之为软链接。
硬链接和软链接最明显的区别在于:
- 删除硬链接指向的其中一个文件后,由于只是将inode节点的链接数减少了 1 1 1,仍有文件指向该inode节点,仍能正常访问其他相同inode节点的文件。
- 删除软链接指向的源文件后,读取链接文件则会报错
No such file or directory
。
第二题
编写C程序,完成将键盘输入的一组整数递减排序后输出到指定的磁盘文件中
/*
* 因为题目说键盘输入一组数,没有说怎么停止
* 那我可以有以下三种解读:
* ① 数据是一行字符串,读取后自行切割转换
* ② 自己拓展——输入-999结束
* ③ 自己拓展——先输入数据个数,再输入个数
* 显然后②③自己拓展虽然好实现,但感觉还是①的理解最符合题目的本意
* */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#define N 1000 // 假定输入的整数个数少于1000
#define I_N 10 // 假定输入的整数长度少于10
char *str = NULL; // 接受输入的C式字符串
int a[N]; // 存储整数的数组
int cnt = 0; // 存储输入整数的个数
size_t len = 0; // 切割字符串长度参数
char *part; // 存储切割部分的字符串
char num[N]; // 存储要每次写入的内容字符串
// 比较函数
int cmp(const void*a, const void*b)
{
return *(int*)(b)-*(int*)(a);
}
int main(int argc, char *argv[])
{
// 读取数组字符串
scanf("%s", str);
getline(&str, &len, stdin);
char* buff = str;
// 用strsep函数切割C式字符串
while ((part = strsep(&buff, " ")) != NULL)
a[cnt++] = atoi(part); // 用atoi函数将C式字符串转换为int并存入数组
// 回收getline由于str为NULL而自动动态分配的空间
free(str);
// 用qsort函数降序排列
qsort(a, cnt, sizeof(int), cmp);
// 将数组写入文件
int fd = open("res-2.txt", O_RDWR | O_CREAT | O_TRUNC, 0755);
if (fd != -1)
{
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;
}
示例截图
第三题
编写程序,可以将两个有序的数据子文件归并到一个有序的结果文件中
(如递减排序,可利用上一题生成整型数据文件)
/*
* 和上面第二题的方法一样
* 只要从两个文件读取出两组输入字符串,拼接成一个字符串
* 就划归到第二题了
* */
#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
char str1[LEN]; // 文件1读取的输入字符串
char str2[LEN]; // 文件2读取的输入字符串
char str[2 * LEN] = ""; // 接受输入的C式字符串
int a[N]; // 存储整数的数组
int cnt = 0; // 存储输入整数的个数
size_t len = 0; // 切割字符串长度参数
char *part; // 存储切割部分的字符串
char num[N]; // 存储要每次写入的内容字符串
// 比较函数
int cmp(const void*a, const void*b)
{
return *(int*)(b)-*(int*)(a);
}
int main(int argc, char *argv[])
{
// 读取两个文件的数组字符串
int fd1 = open("data1.txt", O_RDONLY);
int fd2 = open("data2.txt", O_RDONLY);
if (fd1 == -1 || fd2 == -1)
{
perror("文件打开有误");
exit(1);
}
read(fd1, str1, sizeof(str1) - 1);
read(fd2, str2, sizeof(str2) - 1);
close(fd1);
close(fd2);
// 去掉文尾的换行和空格拼接成为一个字符串
str1[strlen(str1) - 1] = '\0';
str2[strlen(str2) - 2] = '\0';
strcat(str, str1);
strcat(str, str2);
char* buff = str;
// 用strsep函数切割C式字符串
while ((part = strsep(&buff, " ")) != NULL)
a[cnt++] = atoi(part); // 用atoi函数将C式字符串转换为int并存入数组
// 用qsort函数降序排列
qsort(a, cnt, sizeof(int), cmp);
// 将数组写入文件
int fd = open("res-3.txt", O_RDWR | O_CREAT | O_TRUNC, 0755);
if (fd == -1)
{
perror("文件打开有误");
exit(1);
}
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;
}
示例截图
第四题
编写一个程序
listDIR.c
当执行listDIR sub1
时,可以将指定sub1
目录下的所有文件信息,按文件名、类型、长度进行列表
(子目录中的文件不再显示,类型标识是权限码的第一个字符,符号链接文件还需显示inode节点号)
思路一:得到运行参数的路径后,将其置为以/
结尾,需要具体文件路径时再进行拼接
/*
* 考点:目录操作、文件属性获取
* */
#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 path_tmp[LEN] = "";
const char none[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 '-';
}
int main(int argc, char *argv[])
{
// 如果没有传入参数,则默认选择当前目录
if (argc < 2)
strcpy(path, ".");
else
strcpy(path, argv[1]);
// 格式化path,使之以`/`结尾
if (path[strlen(path) - 1] != '/')
strcat(path, "/");
// 打开指定目录
DIR * dir_ptr = opendir(path);
struct dirent * dir;
if (dir_ptr == NULL)
{
perror("目录打开失败");
exit(1);
}
// 读取每一个目录项,构造stat获取其属性
struct stat buf;
printf("%-30s%-20s%-30s%-30s\n", "filename", "type", "length(Byte)", "inode_num");
printf("----------------------------------------------------------------------------------------------------\n");
while ((dir = readdir(dir_ptr)) != NULL)
{
// 构造完整的相对于参数目录的路径
strcpy(path_tmp, none);
strcat(path_tmp, path);
strcat(path_tmp, dir->d_name);
// 构造stat,读取文件属性并说出
int res = lstat(path_tmp, &buf);
if (res == 1)
{
perror("读取文件属性失败");
exit(2);
}
char ch = getType(buf.st_mode);
if (ch == 'l')
printf("%-30s%-20c%-30ld%-30ld\n", dir->d_name, ch, buf.st_size, buf.st_ino);
else
printf("%-30s%-20c%-30ld\n", dir->d_name, ch, buf.st_size);
}
return 0;
}
思路二:得到运行参数的路径后,直接将当前工作目录置为该路径,然后在当前目录.
下直接操作
/*
* 考点:目录操作、文件属性获取
* 【缺陷已修正】:
* 原来直接将参数目录用chdir切换工作目录,如果目录不存在并不会出错而停止运行
* 现在已加上在chdir之前通过access判断目录是否存在
* */
#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 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 '-';
}
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)
{
perror("目录打开失败");
exit(1);
}
// 读取每一个目录项,构造stat获取其属性
struct stat buf;
printf("%-30s%-20s%-30s%-30s\n", "filename", "type", "length(Byte)", "inode_num");
printf("----------------------------------------------------------------------------------------------------\n");
while ((dir = readdir(dir_ptr)) != NULL)
{
// 构造stat,读取文件属性并说出
int res = lstat(dir->d_name, &buf);
if (res == -1)
{
perror("读取文件属性失败");
exit(2);
}
char ch = getType(buf.st_mode);
if (ch == 'l')
printf("%-30s%-20c%-30ld%-30ld\n", dir->d_name, ch, buf.st_size, buf.st_ino);
else
printf("%-30s%-20c%-30ld\n", dir->d_name, ch, buf.st_size);
}
return 0;
}
示例截图