《Linux编程》作业 ·003【文件I/O操作】

注:前言、目录见 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;
}

示例截图
在这里插入图片描述

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

God-Excious

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值