利用read和write实现文件内容的拷贝、主函数传参、文件IO、目录IO

本文详细介绍了嵌入式开发中如何使用Linux系统调用进行文件读写、lseek操作,以及目录创建、删除、遍历和权限检查等技巧。还涉及了主函数参数处理和递归函数的应用。
摘要由CSDN通过智能技术生成

我要成为嵌入式高手之2月19日Linux高编第四天!!
______________________________________________________

练习

练习1:利用read和write实现文件内容的拷贝(将src.jpg中的内容拷贝到dst.jpg文件中)

#ifndef _HEAD_H
#define _HEAD_H

#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>

#endif
#include "head.h"

int main(int argc, const char *argv[])
{
    int src = 0;
    int dst = 0;
    char tmpbuff[4096] = {0};
    ssize_t nret = 0;

    if (argc != 3)
    {
        fprintf(stderr,"Usage: ./a.out srcfilename dstfilename\n");
        return -1;
    }
    
    src = open(argv[1], O_RDONLY);
    if (src == -1)
    {
        perror("fail to open src");
        return -1;
    }

    dst = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0664);
    if (dst == -1)
    {
        perror("fail to open dest");
        return -1;
    }

    while(1)
    {
        nret = read(src, tmpbuff, sizeof(tmpbuff));
        if (nret == 0)
        {
            break;
        }
        write(dst, tmpbuff, nret);
    }

    close(src);
    close(dst);

    return 0;
}

新知识点:主函数传参,在编译之后运行的时候将参数传入主函数

int main (int argc, const char *argv[ ]) 

参数:

        argc:要传的参数个数

        argv:要传的参数的首地址(char* 型)

        cahr *argv[ ]:存放要操作的文件的地址的数组(指针数组)

练习2:1028 人口普查 - PAT (Basic Level) Practice (中文) (pintia.cn)

#include "head.h"

typedef struct person
{
    char name[8];
    char birthday[12];
}person_t;

int main(void)
{
    person_t a[100000];
    int n = 0;
    int i = 0;
    int cnt = 0;
    char maxvalue[12] = {"2014/09/06"};
    char minvalue[12] = {"1814/09/06"};
    int curmax = 0;
    int curmin = 0;

    scanf("%d",&n);

    for (i = 0; i < n; ++i)
    {
        scanf("%s%s",a[i].name,a[i].birthday);
    }

    for (i = 0; i < n; ++i)
    {
        if (strcmp(a[i].birthday,maxvalue) <= 0 && strcmp(a[i].birthday,minvalue) >= 0)
        {
            cnt++;

            if (cnt == 1)
            {
                curmin = curmax = i;
            }

            if (strcmp(a[i].birthday,a[curmax].birthday) > 0)
            {
                curmax = i;
            }

            if (strcmp(a[i].birthday,a[curmin].birthday) < 0)
            {
                curmin = i;
            }
        }
    }

    printf("%d %s %s\n",cnt,a[curmin].name,a[curmax].name);

    return 0;
}

学习笔记

 一、文件IO

lseek

off_t lseek(int fd, off_t offset, int whence);
功能:重新设定文件描述符的偏移量

参数:

        fd:文件描述符

        offset:偏移量

        whence:开始偏移的位置

                SEEK_SET        文件开头

                SEEK_CUR        文件当前位置

                SEEK_END        文件末尾

返回值:成功返回当前偏移量,失败返回-1;

#include "head.h"

int main(void)
{
    int fd = 0;
    off_t len = 0;
    char ch = 0;

    fd = open("a.txt", O_WRONLY | O_CREAT | O_TRUNC, 0664);
    if (-1 == fd)
    {   
        perror("fail to open");
        return -1;
    }

    len = lseek(fd, 10, SEEK_SET);
    printf("len = %ld\n",len);
    ch = 'A';
    write(fd, &ch, 1);

    len = lseek(fd, -5, SEEK_CUR);
    printf("len = %ld\n",len);
    ch = 'B';
    write(fd, &ch, 1);
    
    len = lseek(fd, 0, SEEK_SET);
    printf("len = %ld\n",len);
    ch = 'C';
    write(fd, &ch, 1);

    close(fd);

    return 0;
}

二、目录IO

1、mkdir

#include <sys/stat.h>
#include <sys/types.h>

int mkdir(const char *pathname, mode_t mode);

        功能:创建目录文件

        参数:

                pathname:文件路径

                mode:文件的权限

                rwx  rwx  rwx:x目录是否能进入 w目录是否能新建文件 r目录是否能查看文件

                111 111 111

                 0 7   7    7

        返回值:成功返回0,失败返回-1:

#include "head.h"

int main(void)
{
    mkdir("dir11",0777);
    
    return 0;
}

2、rmdir

#include <unistd.h>

int rmdir(const char *pathname);

功能:删除空目录文件

返回值:成功返回0,失败返回-1

3、opendir

#include <sys/types.h>
#include <dirent.h>

DIR *opendir(const char *name);  (DIR *  目录流指针)

功能:打开目录,获得目录流指针

参数:

        name:目录文件的路径

返回值:成功返回目录流指针,失败返回空

4、closedir

#include <sys/types.h>

#include <dirent.h>

int closedir(DIR *dirp);

功能:关闭目录流指针

5、readdir

#include <dirent.h>

struct dirent *readdir(DIR *dirp);

功能:从目录流中读取下一个目录项的结构体信息

参数:dirp 目录流指针

返回值:

        成功返回包含目录项信息的空间首地址

        失败或者读到文件末尾返回NULL

struct dirent {
               ino_t          d_ino;               /* Inode number */(标号)
               off_t          d_off;                 /* Not an offset; see below */(偏移量)
               unsigned short d_reclen;    /* Length of this record */(大小)
               unsigned char  d_type;       /* Type of file; not supported(文件类型)
                                                              by all filesystem types */
               char           d_name[256];    /* Null-terminated filename */(包含了一个 \ 0 的文件名)
           };

3、4、5使用:

#include "head.h"

int main(void)
{
    DIR *dp = NULL;
    struct dirent *pp = NULL;

    dp = opendir("dir");
    if (dp == NULL)
    {
        perror("fail to opendir");
        return -1;
    }

    while (1)
    {
        pp = readdir(dp);
        if (pp == NULL)
        {
            break;
        }

        if (*pp->d_name == '.')
        {
            continue;
        }
        printf("%s\n",pp->d_name);
    }
    closedir(dp);

    return 0;
}

6、chdir  

#include <unistd.h>

int chdir(const char *path);

功能:切换到path目录工作路径(改变路径)

7、getcwd  

#include <unistd.h>

char *getcwd(char *buf, size_t size);

功能:获得当前目录的绝对路径

6、7使用

#include "head.h"

int main(void)
{
    char tmpbuff[4096] = {0};

    getcwd(tmpbuff,sizeof(tmpbuff));
    printf("tmpbuff = %s\n",tmpbuff);

    chdir("..");
    getcwd(tmpbuff,sizeof(tmpbuff));
    printf("tmpbuff = %s\n",tmpbuff);

    return 0;
}

练习1(难):

递归遍历 

#include "head.h"

int ListDir(const char *pdirname)//遍历pdirname目录下所有文件的信息
{
    DIR *dp = NULL;//接收opendir返回的一个dir型指针
    struct dirent *pp = NULL;//接收readdir返回的结构体
    char tmpbuff[4096] = {0};

    dp = opendir(pdirname);
    if (NULL == dp)
    {
        perror("fail to opendir");
        return -1;
    }

    while (1)
    {
        pp = readdir(dp);
        if (NULL == pp)
        {
            break;
        }

        if ('.' == *pp->d_name)
        {
            continue;
        }

        sprintf(tmpbuff, "%s/%s", pdirname, pp->d_name);
//要读的文件夹的名字和该文件夹下所有文件的名字,组合而成就是路径,将该路径存入tmpbuff中
        printf("%s\n",tmpbuff);

        if (pp->d_type == DT_DIR)//D_TYPE文件类型,文件类型为DT_DIR(文件夹类型)时,再次调用函数
        {
            ListDir(tmpbuff);//递归调用
        }
    }
    closedir(dp);

    return 0;
}

int main(int argc, const char *argv[])
{
    if (argc != 2)
    {
        fprintf(stderr,"Usage: ./a.out dirname\n");
        return -1;
    }

    ListDir(argv[1]);

    return 0;
}

6、accsee

#include <unistd.h>

int access(const char *pathname, int mode);

功能:检测调用函数的程序对文件是否拥有指定权限

参数:

        pathname:文件路径

        mode:

                R_OK        是否拥有读权限

                W_OK        是否拥有写权限

                X_OK        是否拥有执行权限

                F_OK        是否存在

返回值:有该权限返回0,没有返回-1;

#include "head.h"

int main(int argc,const char *argv[])
{
    int ret = 0;

    if (argc != 2)
    {
        fprintf(stderr,"Usage: ./a.out filename\n");
        return -1;
    }

    ret = access(argv[1],F_OK);
    if (ret == 0)
    {
        printf("该文件存在!\n");
    }else
    {
        printf("该文件不存在!\n");
    }

    return 0;
}

 练习2(难):

        编写一个程序,分两次执行,第一次执行后,再次执行时打印出两个执行过程中间,指定目录下新增的文件及删除的文件

#include "head.h"

#define RECORD_PATH     "record.bk"

int ListDir(const char *pdirname,FILE *file)//每次递归调用仍然传的是流指针,流指针具有偏移量,会随着写入自动向后增加

{
    DIR *dp = NULL;
    struct dirent *pp = NULL;
    char tmpbuff[1024] = {0};

    dp = opendir(pdirname);
    if (NULL == dp)
    {
        perror("fail to opendir");
        return -1;
    }

    while (1)
    {
        pp = readdir(dp);
        if (NULL == pp)
        {
            break;
        }

        if ('.' == *pp->d_name)
        {
            continue;
        }

        sprintf(tmpbuff,"%s/%s", pdirname, pp->d_name);
        fprintf(file, "%s\n", tmpbuff);

        if (DT_DIR == pp->d_type)//判断文件类型若为文件夹类型
        {
            ListDir(tmpbuff, file);//递归调用
        }
    }

    closedir(dp);

    return 0;
}

int ListDirToRecord(const char *pdirname)//第一次执行
{
    FILE *fp = NULL;

    fp = fopen(RECORD_PATH,"w");
    if (fp == NULL)
    {
        perror("fail to fopen");
        return -1;
    }

    ListDir(pdirname, fp);//遍历到的结果写入流中
    fclose(fp);
    return 0;
}

int ShowDeleteFiles(void)
{
    FILE *fp = NULL;
    char tmpbuff[4096] = {0};
    char *pret = NULL;

    fp = fopen(RECORD_PATH, "r");//打开dk文件检查是否存在
    if (NULL == fp)
    {
        perror("fail to fopen");
        return -1;
    }

    while (1)//判断读取到的全部文件是否存在,直到文件末尾
    {
        pret = fgets(tmpbuff, sizeof(tmpbuff), fp);//每次读取一行
        if (NULL == pret)//文件末尾
        {
            break;
        }

        tmpbuff[strlen(tmpbuff)-1] = '\0';//fgets读到\n停止,但是文件名里没有\n,故应该去掉\n
    //tmpbuff[strlen(tmpbuff)] \0的位置
        if (access(tmpbuff, F_OK) != 0)//判断读取到的文件是否存在
        {
            printf("%s\n",tmpbuff);//打印不存在的文件
        }
    }
    fclose(fp);

    return 0;
}

int IsNewFile(char *pfilepath)//判断新的文件pfliepath在dk列表里是否出现过
{
    FILE *fp = NULL;
    char tmpbuff[4096] = {0};
    char *pret = NULL;


    fp = fopen(RECORD_PATH, "r");
    if (NULL == fp)
    {
        perror("fail to fopen");
        return -1;
    }

    while (1)//判断文件的每一行与pfilepath是否相同
    {
        //读一行,置成\0,判断相不相同,相同则不是新文件,直到文件末尾也不相同,就是新文件
        pret = fgets(tmpbuff, sizeof(tmpbuff), fp);
        if (pret == NULL)//读到文件末尾
        {
            break;
        }

        tmpbuff[strlen(tmpbuff)-1] = '\0';//读到的有换行,需要将换行置成\0

        if (strcmp(tmpbuff, pfilepath) == 0)
        {
            fclose(fp);
            return 0;
        }
    }

    fclose(fp);
    
    return 1;//没有return0 确实是新文件,return1
}

int ListDir2(const char *pdirname)//不需要写入,只需要查找
{
    DIR *dp = NULL;
    struct dirent *pp = NULL;
    char tmpbuff[1024] = {0};

    dp = opendir(pdirname);
    if (NULL == dp)
    {
        perror("fail to opendir");
        return -1;
    }

    while (1)
    {
        pp = readdir(dp);
        if (NULL == pp)
        {
            break;
        }

        if ('.' == *pp->d_name)
        {
            continue;
        }

        sprintf(tmpbuff,"%s/%s", pdirname, pp->d_name);
        if (IsNewFile(tmpbuff))//判断是不是新的文件
        {
            printf("%s\n",tmpbuff);//若为新的文件,就进行打印
        }

        if (DT_DIR == pp->d_type)//判断文件类型若为文件夹类型
        {
            ListDir2(tmpbuff);//递归调用
        }
    }

    closedir(dp);

    return 0;
}

int ShowNewFiles(const char *pdirname)
{
    ListDir2(pdirname);
    
    return 0;
}

int main(void)
{
    int ret = 0;

    ret = access(RECORD_PATH, F_OK);
    if (ret == 0)
    {
        printf("删除的文件:\n");
        ShowDeleteFiles();
        printf("新增的文件:\n");
        ShowNewFiles(".");
    }else
    {
        ListDirToRecord(".");
    }
}

  • 22
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值