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

本文介绍了三个C语言程序,分别实现了Linux cp命令的模拟,对无序数据文件进行升序或降序排序,以及列出指定目录下所有文件的权限码、文件名和长度。通过读取文件、内存操作和文件写入,展示了基本的文件处理技巧和排序算法的应用。
摘要由CSDN通过智能技术生成

注:前言、目录见 https://blog.csdn.net/qq_44220418/article/details/108428971

友情提醒:仅供参考理解,请勿直接复制粘贴

友情提醒:仅供参考理解,请勿直接复制粘贴

友情提醒:仅供参考理解,请勿直接复制粘贴

第一题

模拟Linux的cp命令
编写一个C语言程序,该程序产生的可执行文件名为cpx,其功能类似于cp命令。


当执行cpx A BAB为任意两个文件名)时,会将文件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)排序后输出到指定的磁盘文件中。


如:
\qquad userdata.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;
}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

God-Excious

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

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

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

打赏作者

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

抵扣说明:

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

余额充值