实现fast-cp :拷贝文件到目标对象

Linux的七种文件类型 :https://blog.csdn.net/linkvivi/article/details/79834143

   ls -al :https://www.cnblogs.com/fyc119/p/6959695.html

   文件的属性有三类权限 , 文件拥有者权限 ,  文件拥有者组的权限 , 其他权限 : https://www.cnblogs.com/xiaoxiaoweng/p/10722044.html

          chmod abc file  abc分别表示User、Group、及Other的权限  file表示修改的文件 , 每类都有三种权限 rwx

          r=4,w=2,x=1

          若要rwx属性则4+2+1=7;

          若要rw-属性则4+2=6;

          若要r-x属性则4+1=5。

stat()  https://www.cnblogs.com/Demo1589/p/7845017.html

分三个模块

1.文件操作模块: 也就是POSIX文件操作和目录管理

  1.1 文件状态 :当前文件是否存在

  1.2 文件属性 :权限属性,类型属性...

        文件的类型 :是指电脑为了存储信息而使用的对信息的特殊编码方式,是用于识别内部储存的资料 (设备文件 , 常规文件)

        文件的权限 :读写权限

2.核心IO模式

  2.1发起aio读

  2.2在aio_read的回调函数里发起aio_write(根据偏移量,分段读和写(业务逻辑,生产者和消费者的关系,有读才有写)) , aio_write里sem_post(计时)

3.辅助模块

  程序计时的实现 : 在程序开始时 设置 struct timespec tv1 , tv2; 使用clock_gettime(CLOCK_MONOTONIC , &tv1);获得当前系统时间 , 再在程序结束前再次获取clock_gettime(CLOCK_MONOTONIC , &tv2)结束计时; tv2 - tv1 = 程序的执行时长 ,

          但因为程序里的文件操作(AIO)是非阻塞的, 而且有多个文件(AIO) , 所以要使用同步机制 sem_t blocking_waiter(同步信号量)  , 同步机制: 计时的结束必须要在程序拷贝(AIO)之后完成 , 如: 因为aio是非阻塞的 , 所以在多线程的情况下主线程的计时结束应该在aio的内核线程完成后再结束计时 ,而实现这个同步机制的关键是sem_t blocking_waiter , 在开始计时时  sem_init(&blocking_waiter , 0 ,0) , blocking_waiter 可以看做是一个公共资源 , sem_wait()是阻塞的 它会在blocking_waiter里-1 ,而sem_post() 会在blocking_waiter 里+1只有blocking_waiter >= 0时sem_wait才会返回

sem_t blocking_writer;
sem_init(&blocking_waiter , , ); //第二个参数使用默认0 , 多线程
clock_gettime(CLOCK_MONOTINIC , &tv1);
sem_post(&blocking_waiter); //在aio的回调函数里使用
sem_wait(&blocking_waiter); //在主线程里使用
clock_gettime(CLOCK_MONOTINIC , &tv2
struct stat 
{  
   dev_t st_dev; /* 设备号码 特殊的文件*/ 
    ino_t     st_ino;     /* inode节点号 常规的文件*/
mode_t st_mode; /* 文件对应的模式 , 文件 , 目录等 */
nlink_t st_nlink; /* 文件的连接数*/
uid_t st_uid; /* 文件的所有者 */
gid_t st_gid; /* 文件所有者对应的组 */
dev_t st_rdev; /* 特殊设备号码 */
off_t st_size; /* 普通文件 , 对应文件字节数 */
blksize_t st_blksize; /* 文件内容对应的块大小 , 比如磁盘的读写单位都是按块计算的*/
blkcnt_t st_blocks; /* 文件内容对应块的数量 */
time_t st_atime; /* 文件最后被访问的时间 */
time_t st_mtime; /* 文件最后被修改的时间 */
time_t st_ctime; /* 文件状态改变的时间 */
}; S_ISLNK(st_mode):是否是一个连接.
S_ISREG(st_mode):是否是一个常规文件.
S_ISDIR(st_mode):是否是一个目录
S_ISCHR(st_mode):是否是一个字符设备.
S_ISBLK(st_mode):是否是一个块设备
S_ISFIFO(st_mode):是否是一个FIFO文件.
S_ISSOCK(st_mode):是否是一个SOCKET文件 

 S_IRUSR:用户读权限

 S_IWUSR:用户写权限

 S_IRGRP:用户组读权限

 S_IWGRP:用户组写权限

 S_IROTH:其他组都权限

 S_IWOTH:其他组写权限

4.实现流程:

  4.1 辅助模块的使用 , 创建时间对象struct timespec tv1, tv2; 程序开始计时获取系统时间clock_gettime(CLOCK_MONOTONIC, &tv1);

    初始一个信号量clock_gettime(CLOCK_MONOTONIC, &tv1); , 配合sem_post() , sem_wait()使用 , 当sem_wait() >= 0 时程序才继续运行 把读写操作完成

    才返回,否则阻塞 , 当sem_wait()返回后销毁信号量 , 再次获取系统时间 clock_gettime(CLOCK_MONOTONIC, &tv2); , tv2-tv1 = 程序运行的时长

  4.2 文件操作模块,     获取源文件信息if(stat(src , src_stat) == -1) 失败返回-1并结束程序 , 获取目标信息时if (stat(dst, &dst_stat) == -1) 失败返回-1说明目标不是一个文件 , 可能是个目录或其他的东西. 错误代码存在errorif , if (errno != ENOENT) 如果出错,一定是因为没有输入 ,

    errno != ENOENT :报错不是因为没有这个路径或文件, 是其他的错误那么一定是没有输入目标

    如果输入了判断其是否是一个目录if (S_ISDIR(src_stat.st_mode)) , 如果是一个目录且存在则不用做其他操作直接打开目录opendir(dir);并往里复制源文件

     traverse_dir_copy(src);  如果不存在则创建目录并设置读写执行权限if(mkdir(dst, S_IRWXU | S_IRWXG) == -1)并往里复制源traverse_dir_copy(src);

    如果if (stat(dst, &dst_stat) == -1) 返回成功,说明目标是一个文件, 直接赋值文件到目标里copy_regular(src, dst);,不存在则创建文件后再复制

  4.3 核心IO模块,  获取源信息if (stat(src_file, &stat_buf) == -1 ),并打开if ((src_fd = open(src_file, O_RDONLY)) < 0) ,因为经过上述的判断, 目标是一个文件

    所以创建并以写入的方式打开 if ((dst_fd = open(dst_file, O_WRONLY| O_CREAT, stat_buf.st_mode)) < 0)并附上和写相同的权限 , 创建之后获取目标的信息

    因为确定目标是一个文件所以可以以if (fstat(dst_fd, &stat_dst) == -1)文件的方式获取 , 判断源和目标的设备号且inode节点号是否一致, 两个一致证明是

    相同文件可以直接退出程序 ,

    posix_fadvise(src_fd, 0, stat_buf.st_size, POSIX_FADV_WILLNEED); 预分配内存 :在做大量拷贝时, 预分配内存会提高读写效率 , 因为预分配的是一块大的

    内存,再从里面分配小块的内存,这些小的内存是连续的 , 而直接malloc的可能是不连续的, 这样就避免了内核分配内存时过于繁琐 , 从而提高了效率

    if (fallocate(dst_fd, 0, 0, stat_buf.st_size) == -1);    分配预定大小的内存 , 之后的malloc都会从分配好的大块内存中拿一块小的给malloc直到分配完

    文件较大时分段拷贝(多开几个AIO)可以有效的提高效率 , 其中按页开始分段(一页4K) , 根据偏移值来分段,

    获取页大小page_size = getpagesize(); 获取页的数量num_pages = stat_buf.st_size / page_size + 1; +1是预防非整页而多出来的比如4页多出一两个字符

    一次需要读取或者写入的大小buffer_size = page_size; 开始读取和写入for (i = 0; i < stat_buf.st_size; i += buffer_size)

typedef struct handler_context
{
struct aiocb* m_aiocb; //需要异步操的对象
size_t m_offset; //偏移量
size_t m_file_size; //文件大小
int m_src_fd; //源文件fd
int m_dst_fd; //目标文件fd
} handler_context;

    循环里发起AIO 并 设置分配 handler_context对象 和 aiocb对象

 struct aiocb* r_aiocb = (struct aiocb*)malloc(sizeof(struct aiocb));
handler_context* r_context = (handler_context *) malloc(sizeof(handler_context));
bzero ((char *)r_context, sizeof(handler_context));
bzero ((char *)r_aiocb, sizeof(struct aiocb)); // context to be passed to handler
r_context->m_aiocb = r_aiocb;
r_context->m_offset = i;
r_context->m_file_size = stat_buf.st_size;
r_context->m_src_fd = src_fd;
r_context->m_dst_fd = dst_fd; // basic setup
r_aiocb->aio_fildes = src_fd;
r_aiocb->aio_nbytes = buffer_size;
r_aiocb->aio_offset = i;
r_aiocb->aio_buf = buffer_block; // thread callback
r_aiocb->aio_sigevent.sigev_notify = SIGEV_THREAD;
r_aiocb->aio_sigevent.sigev_notify_function = aio_read_handler;
r_aiocb->aio_sigevent.sigev_notify_attributes = NULL;
r_aiocb->aio_sigevent.sigev_value.sival_ptr = (void *)r_context;

    aio_read() 后 aio_read_handler回调函数 里再调用 aio_write_handler回调函数 并 aio_write() ++lock_num_requests; sem_post(&blocking_waiter);

  4.4目录拷贝

    先判断当前目标是否是一个目录 S_ISDIR , 在通过opendir(char *dir)判断当前目录是否存在,能open说明存在 , 直接开始拷贝目录traverse_dir_copy(src) ,

    反之则不存在 ,目录不存在则先创建目录if(mkdir(dst, S_IRWXU | S_IRWXG) == -1)RWX代表权限 ,U代表用户 ,G代表用户组 , 创建好目录后 , 再进行目录的

    拷贝traverse_dir_copy(src) , 目录的拷贝只要做两件事就可以了 , 1.获取目录list (目录和文件都有一个自己的结构体对象,目录的是dir_entry) , 具体的获取

    1.DIR * p = opendir(pdir);获得源目录并创建一个dirent结构体对象 , 2.读取目录while((q=readdir(p))!=NULL), readdir()并不是全部获得只能获取一个 , 比如A目录有B ,C; 第一次只会获得B , 第二次readdir会获得C , 内核会实现这样的机制, 我们只要多次readdir就行了 . 获取之后判断获得的那一个是否带点(.)开头的目录或文件

    Linux里以点开头的文件都叫隐藏文件 , 而点代表当前目录,点点代表上级目录 ,所以点开头if(q->d_name[0] == '.')的文件都continue跳过 , 不需要拷贝

#define DT_UNKNOWN    0    //未知的
#define DT_FIFO 1 //管道
#define DT_CHR 2 //字符设备文件
#define DT_DIR 4 //目录
#define DT_BLK 6 //块设备文件
#define DT_REG 8 //普通文件
#define DT_LNK 10 //链接
#define DT_SOCK 12 //sockt文件
#define DT_WHT 14

  struct dirent {
      ino_t d_ino; /* inode number 索引节点号*/
      off_t d_off; /* not an offset; see NOTES 在目录文件中的偏移*/
      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]; /* filename 文件名,最长255字符*/

  };

  判断当前文件的类型if(q->d_type==DT_REG)如果是一个常规文件则进行常规文件的拷贝 , 如果还是目录else if ( q->d_type==DT_DIR)

  在目标目录里继续创建子目录if(mkdir(dst_dir, S_IRWXU | S_IRWXG) == -1) 再递归调用自己,继续遍历子目录 traverse_dir_copy(my_path);

具体代码实现:

// TODO arrange in alphabetical order, separated by type
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <aio.h>
#include <semaphore.h>
#include <dirent.h>
#include <errno.h>
#include <time.h> #define MAX_PATH 256 size_t buffer_size; //一次需要读取或者写入的大小
uint64_t page_size; //文件读取时的页数
int lock_num_requests;
//信号量通知
sem_t blocking_waiter; //目录文件路径
char * src;
char * dst; char *tem_buf; void aio_read_handler (sigval_t sigval);
void aio_write_handler(sigval_t signal);
char *format_path(char* path) ;
char* Find_Last_dir_Path(char * path);
int is_exist_dir(char* _dir);
void traverse_dir_copy(char * pdir);
char * split_str(char *path,char *src_path,char **result); //目录或文件需要复制的结构体对象
typedef struct handler_context
{
struct aiocb* m_aiocb; //需要异步操的对象
size_t m_offset; //偏移量
size_t m_file_size; //文件大小
int m_src_fd; //源文件fd
int m_dst_fd; //目标文件fd
} handler_context; /*****************************************************************************
函 数 名 : aio_read_handler
功能描述 : aio异步读取函数
输入参数 : sigval_t sigval
输出参数 : 无
返 回 值 : void
调用函数 :
被调函数 : 修改历史 :
1.日 期 : 2017年8月12日
作 者 : xiaofeng
修改内容 : 新生成函数 *****************************************************************************/
void aio_read_handler (sigval_t sigval)
{
size_t nbytes;
size_t w_nbytes = ;
handler_context* hctx = (handler_context*)sigval.sival_ptr;
if (aio_error(hctx->m_aiocb))
{
perror("read aio error");
exit(-);
}
nbytes = aio_return(hctx->m_aiocb);
int i = ;
void * buffer = (void *)hctx->m_aiocb->aio_buf;
/*w_nbytes = pwrite(hctx->m_dst_fd, buffer, nbytes, hctx->m_offset);
if (w_nbytes != nbytes) {
perror("sync write error");
exit(-1);
}
sem_post(&blocking_waiter);*/
// now send an async write request for the destination file
// init aiocb struct
struct aiocb* w_aiocb = (struct aiocb*)malloc(sizeof(struct aiocb));
handler_context* w_context = (handler_context *) malloc(sizeof(handler_context));
bzero ((char *)w_context, sizeof(handler_context));
bzero ((char *)w_aiocb, sizeof(struct aiocb)); // context to be passed to handler
w_context->m_aiocb = w_aiocb;
w_context->m_offset = hctx->m_offset;
w_context->m_file_size = hctx->m_file_size;
w_context->m_src_fd = hctx->m_src_fd;
w_context->m_dst_fd = hctx->m_dst_fd; // basic setup
w_aiocb->aio_fildes = hctx->m_dst_fd;
w_aiocb->aio_nbytes = nbytes;
w_aiocb->aio_offset = hctx->m_offset;
w_aiocb->aio_buf = buffer; // thread callback
w_aiocb->aio_sigevent.sigev_notify = SIGEV_THREAD;
w_aiocb->aio_sigevent.sigev_notify_function = aio_write_handler;
w_aiocb->aio_sigevent.sigev_notify_attributes = NULL;
w_aiocb->aio_sigevent.sigev_value.sival_ptr = (void *)w_context; if (aio_write(w_aiocb) < )
{
perror("aio_write error");
exit(-);
}
++lock_num_requests;
sem_post(&blocking_waiter);
} /*****************************************************************************
函 数 名 : aio_write_handler
功能描述 : aio异步写入函数
输入参数 : sigval_t sigval
输出参数 : 无
返 回 值 : void
调用函数 :
被调函数 : 修改历史 :
1.日 期 : 2017年8月12日
作 者 : xiaofeng
修改内容 : 新生成函数 *****************************************************************************/
void aio_write_handler (sigval_t sigval)
{
size_t nbytes;
handler_context* hctx = (handler_context*)sigval.sival_ptr;
if (aio_error(hctx->m_aiocb))
{
perror("write aio error");
exit(-);
}
nbytes = aio_return(hctx->m_aiocb);
sem_post(&blocking_waiter);
//free(hctx->m_aiocb->aio_buf);
} /*****************************************************************************
函 数 名 : copy_regular
功能描述 : aio异步文件复制
输入参数 : const char* src_file
const char* dst_file
输出参数 : 无
返 回 值 : int
调用函数 :
被调函数 : 修改历史 :
1.日 期 : 2017年8月11日
作 者 : xiaofeng
修改内容 : 新生成函数 *****************************************************************************/
int copy_regular (const char* src_file, const char* dst_file)
{ //源文件句柄和目标文件句柄
int src_fd;
int dst_fd; //内存页数和块内存指针
uint64_t num_pages;
void * buffer_block; // get the page_size for the system
page_size = getpagesize(); struct stat stat_buf, stat_dst;
// stat the source file
if (stat(src_file, &stat_buf) == - )
{
perror("source file stat error");
exit(-);
}
// if its a directory, create and exit
// if (S_ISDIR(stat_buf.st_mode))
// {
// if (mkdir(dst_file, S_IRWXU | S_IRWXG))
// {
// perror("mkdir error");
// exit(-1);
// }
// return 0;
// }
// open the source file for reading RDONLY
if ((src_fd = open(src_file, O_RDONLY)) < )
{
perror("source file open error");
exit(-);
}
// open the destination file for writing,没有就创建,并附加上权限
if ((dst_fd = open(dst_file, O_WRONLY| O_CREAT, stat_buf.st_mode)) < )
{
perror("destination file open error");
exit(-);
} if (fstat(dst_fd, &stat_dst) == -)
{
perror("fstat destination error");
exit(-);
} // check if input and output are the same,输入输出是否相同
if (stat_buf.st_dev == stat_dst.st_dev && \
stat_buf.st_ino == stat_dst.st_ino)
return ; // TODO tell the kernel that we will need the input file
posix_fadvise(src_fd, , stat_buf.st_size, POSIX_FADV_WILLNEED); // more efficient space allocation via fallocate for dst file
if (fallocate(dst_fd, , , stat_buf.st_size) == -)
perror("destination file fallocate"); // decide the number of pages in the input file and malloc a buffer accordingly
num_pages = stat_buf.st_size / page_size + ;
buffer_size = page_size;
//(num_pages < BUF_MAX) ? (num_pages * page_size) : (BUF_MAX * page_size); // now start sending aio read requests
size_t i;
for (i = ; i < stat_buf.st_size; i += buffer_size)
{
//posix_fadvise(src_fd, i, buffer_size, POSIX_FADV_SEQUENTIAL);
buffer_block = (void *)malloc(buffer_size);
if (errno == ENOMEM)
{
perror("malloc for buffer error");
exit(-);
}
// init aiocb struct
struct aiocb* r_aiocb = (struct aiocb*)malloc(sizeof(struct aiocb));
handler_context* r_context = (handler_context *) malloc(sizeof(handler_context));
bzero ((char *)r_context, sizeof(handler_context));
bzero ((char *)r_aiocb, sizeof(struct aiocb)); // context to be passed to handler
r_context->m_aiocb = r_aiocb;
r_context->m_offset = i;
r_context->m_file_size = stat_buf.st_size;
r_context->m_src_fd = src_fd;
r_context->m_dst_fd = dst_fd; // basic setup
r_aiocb->aio_fildes = src_fd;
r_aiocb->aio_nbytes = buffer_size;
r_aiocb->aio_offset = i;
r_aiocb->aio_buf = buffer_block; // thread callback
r_aiocb->aio_sigevent.sigev_notify = SIGEV_THREAD;
r_aiocb->aio_sigevent.sigev_notify_function = aio_read_handler;
r_aiocb->aio_sigevent.sigev_notify_attributes = NULL;
r_aiocb->aio_sigevent.sigev_value.sival_ptr = (void *)r_context; if (aio_read(r_aiocb) < )
{
perror("aio_read error");
exit(-);
}
++lock_num_requests;
}
return ;
} /*****************************************************************************
函 数 名 : main
功能描述 : 主函数
输入参数 : int argc
char * argv[]
输出参数 : 无
返 回 值 : int
调用函数 :
被调函数 : 修改历史 :
1.日 期 : 2017年8月12日
作 者 : xiaofeng
修改内容 : 新生成函数 *****************************************************************************/
int main(int argc, char * argv[])
{
if (argc != )
{
printf("usage : %s <source> <destination>\n.", argv[]);
return ;
}
//时间对象
struct timespec tv1, tv2;
lock_num_requests = ;
//文件开始复制前的时间
clock_gettime(CLOCK_MONOTONIC, &tv1);
//初始化信号量
sem_init(&blocking_waiter, , );
uint64_t i;
//格式化文件路径
src = argv[];
dst = argv[]; //获取源文件的属性
struct stat src_stat, dst_stat;
if (stat(src, &src_stat) == -)
{
perror("source file stat error");
exit(-);
} //获得目标文件的属性 ,获取失败说明目标并非是文件可能是目录或其他的
if (stat(dst, &dst_stat) == -)
{
// if error, must be because of a no entry
if (errno != ENOENT) //报错说明未输入 , 并非是目录不存在
{
perror("destination file stat error");
exit(-);
}
/*
如果源文件是个目录
*/
if (S_ISDIR(src_stat.st_mode))
{
int iRet = is_exist_dir(dst); //判断目录是否存在
if ( iRet == )
{
printf("the dest alread exist the same directory.\n");
traverse_dir_copy(src); //进入目录,并拷贝文件到目标
}
else
{
//S_IRWXU 00700权限,代表该文件所有者拥有读,
//S_IRWXG 00070权限,代表该文件用户组拥有读,
//创建一个目录, 所有者和所有组有读
if(mkdir(dst, S_IRWXU | S_IRWXG) == -) //创建目录
{
perror("destination mkdir failed");
exit(-);
}
/*遍历并拷贝*/
traverse_dir_copy(src); //进入目录,并拷贝文件到目标
}
}
else
copy_regular(src, dst); //是个文件
} for (i = ; i < lock_num_requests; ++i) //lock_num_requests信号量里有多少个post
{
sem_wait(&blocking_waiter); //sem_wait对应的信号量,如果blocking_waiter >= 0 sem_wait返回否则一直阻塞
} sem_destroy(&blocking_waiter);
clock_gettime(CLOCK_MONOTONIC, &tv2); uint64_t tv = (tv2.tv_sec - tv1.tv_sec) * + tv2.tv_nsec -tv1.tv_nsec;
printf("completion time = %ld.%06ld s\n", tv / , tv % );
return ;
} /*****************************************************************************
函 数 名 : Find_Last_dir_Path
功能描述 : 查找原路径中的最后一个目录
输入参数 : char * path
输出参数 : 无
返 回 值 : char*
调用函数 :
被调函数 : 修改历史 :
1.日 期 : 2017年8月12日
作 者 : xiaofeng
修改内容 : 新生成函数 *****************************************************************************/
char* Find_Last_dir_Path(char * path)
{
char *temp = (char*)malloc(strlen(path)+);
strcpy(temp,path);
int i = ;
for(i = strlen(path) - ; ;i--)
{
if(temp[i] == '/')
break;
}
temp[i]=;
char *result = (char*)malloc(strlen(&temp[i + ])+);
strcpy(result,&temp[i + ]);
result[strlen(result) -] = ;
free(temp);
return result;
} /*****************************************************************************
函 数 名 : is_exist_dir
功能描述 : 判断该路径含有的目录是否存在
输入参数 : char* _dir
输出参数 : 无
返 回 值 : int
调用函数 :
被调函数 : 修改历史 :
1.日 期 : 2017年8月12日
作 者 : xiaofeng
修改内容 : 新生成函数 *****************************************************************************/
int is_exist_dir(char* _dir)
{
DIR * dir = NULL;
dir = opendir(_dir);
if(dir == NULL)
{
closedir(dir);
return ;
}
else
{
closedir(dir);
return ;
}
} /*****************************************************************************
函 数 名 : traverse_dir_copy
功能描述 : 递归遍历目录并复制
输入参数 : char * pdir
输出参数 : 无
返 回 值 : void
调用函数 :
被调函数 : 修改历史 :
1.日 期 : 2017年7月23日
作 者 : xiaofeng
修改内容 : 新生成函数 *****************************************************************************/
void traverse_dir_copy(char * pdir)
{
//打开指定目录,并取得一个目录流指针
DIR * p = opendir(pdir);
//如果错误,直接返回
if ( NULL == p )
{
perror("opendir is error");
return;
}
//定一个目录结构体对象
struct dirent *q;
//定一个文件属性结构体对象
struct stat s; //定义起始目录路径存放变量
char my_path[MAX_PATH];
//定义目的目录路径存放变量
char des_path[MAX_PATH];
//定义临时目录路径存放变量
char tmp_path[MAX_PATH];
strcpy(my_path,pdir);
strcpy(tmp_path,pdir); //定义起始文件路径存放变量
char file_name[MAX_PATH];
//定义临时文件路径存放变量
char tmp_name[MAX_PATH];
strcpy(file_name,pdir);
strcpy(tmp_name,pdir); //目标目录
char dst_dir[MAX_PATH];
char dst_temp[MAX_PATH];
strcpy(dst_dir,dst);
strcpy(dst_temp,dst); //目标目录存放文件
char dst_dir_name[MAX_PATH];
char dst_temp_name[MAX_PATH];
strcpy(dst_dir_name,dst);
strcpy(dst_temp_name,dst); //读取目录
while((q=readdir(p))!=NULL)
{
//遇到'.' '..'直接过滤掉
if(q->d_name[] == '.')
continue;
//这个地方可以添加其他文件属性,这里就不添加了
//判断资源属性,为普通文件
if(q->d_type==DT_REG)
{
//sprintf(des_name,"/%s",q->d_name);
strcat(file_name,q->d_name);
//剔除源文件路径
char *file_adr = (char*)malloc(MAX_PATH);
split_str(file_name,src,&file_adr);
strcat(dst_dir_name,file_adr);
free(file_adr);
//有文件就复制
copy_regular(file_name, dst_dir_name);
//还原原始的路径
strcpy(file_name,tmp_name);
strcpy(dst_dir_name,dst_temp_name); }
else if ( q->d_type==DT_DIR) //判断资源属性,为目录
{
sprintf(des_path,"%s/",q->d_name);
strcat(my_path,des_path);
char *file_adr = (char*)malloc(MAX_PATH);
//char * file_adr = split_str(my_path,pdir);
split_str(my_path,pdir,&file_adr);
strcat(dst_dir,file_adr);
free(file_adr);
//sprintf(dst_path,"/%s",file_adr);
//递归调用自己,继续遍历子目录
if(mkdir(dst_dir, S_IRWXU | S_IRWXG) == -)
{
perror("destination mkdir failed");
exit(-);
} memset(des_path,,sizeof(MAX_PATH)); traverse_dir_copy(my_path);
strcpy(my_path,tmp_path);
strcpy(dst_dir,dst_temp);
}
}
puts("\n");
closedir(p);
} /*****************************************************************************
函 数 名 : split_str
功能描述 : 剥离源路径后剩下的文件和目录名就是需要复制新建的
输入参数 : char *path
char *src_path
char **result
输出参数 : 无
返 回 值 : char *
调用函数 :
被调函数 : 修改历史 :
1.日 期 : 2017年8月12日
作 者 : xiaofeng
修改内容 : 新生成函数 *****************************************************************************/
char * split_str(char *path,char *src_path,char **result)
{
int i = ;
char *temp = (char*)malloc(strlen(path)+);
strcpy(temp,path);
for(i = ;;i++)
{
if(temp[i] != src_path[i])
break;
}
temp[i - ] = ;
strcpy(*result,&temp[i]);
free(temp);
return *result;
}

fast-copy

 


总结:  

Linux基础(10)AIO项目设计与POSIX文件操作和目录管理的更多相关文章

  1. Linux(C/C++)下的文件操作open、fopen与freopen via Boblim

    Linux(C/C++)下的文件操作open.fopen与freopen open是linux下的底层系统调用函数,fopen与freopen c/c++下的标准I/O库函数,带输入/输出缓冲. li ...

  2. Linux 文件基本属性与目录管理 (chmod chown ls cp mv cat )

    Linux 文件基本属性 Linux系统是一种典型的多用户系统,不同的用户处于不同的地位,拥有不同的权限. 为了保护系统的安全性,Linux系统对不同的用户访问同一文件(包括目录文件)的权限做了不同的 ...

  3. Linux基础(09)aio高级编程

    1.出于安全性 Linux有一个机制 应用层和内核层是无法互相直接读取内存的, 他们要互相读取数据是有一个拷贝过程的, 如: 应用层要读取内核层的数据就调用read(), 内核就会先把数据copy到一 ...

  4. 【linux基础】CMake如何生成动态链接库文件

    CMakeLists.txt SET(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/lib) ADD_LIBRARY(filename SHARED ${CURREN ...

  5. Linux基础命令---mput上传ftp文件

    mput 使用lftp登录ftp服务器之后,可以使用put指令将文件上传到服务器.mput指令可以使用通配符,而put指令则不可以.   1.语法       mput [-c]  [-d] [-a] ...

  6. Linux基础命令---put上传ftp文件

    put 使用lftp登录ftp服务器之后,可以使用put指令将文件上传到服务器.   1.语法       put [-E]  [-a]  [-c] [-O base]  lfile  [-o rfi ...

  7. 『学了就忘』Linux基础 — 10、VMware虚拟机中克隆的使用

    目录 1.什么是克隆 2.克隆的两种类型 (1)完整克隆 (2)链接克隆 3.克隆操作 步骤一:克隆虚拟机 步骤二:进行克隆导向 3.快照与克隆的区别 4.镜像的管理 快照和克隆是VMware中两个非 ...

  8. Linux 学习记录 一(安装、基本文件操作).

         Linux distributions主要分为两大系统,一种是RPM方式安装软件的系统,包括Red Hat,Fedora,SuSE等都是这类:一种则是使用Debian的dpkg方式安装软件的 ...

  9. Linux 学习记录一(安装、基本文件操作).

    Linux 名字的由来,是当时作者将初版的 Linux 发布在网上,供别人下载完善,而那个核心文件夹就叫 Linux,就这么叫着了.而为什么 Linux 的吉祥物是一只企鹅呢?是因为当时大家要发行稳定 ...

随机推荐

  1. ESA2GJK1DH1K微信小程序篇: 测试微信小程序APUConfig给WI-Fi模块配网并绑定设备,并通过MQTT控制设备

    前言(源码使用介绍在最后) 一,微信小程序篇小程序下载(该源码为这节测试源代码) 二.有多少人一直在期盼着小程序可以实现SmartConfig或者Airkiss的功能? 来吧!我的这种方式包您满意. ...

  2. Problem 1 珠江夜游 (cruise .cpp)———2019.10.6

    Problem 1 珠江夜游 (cruise.cpp)[题目描述]小 Z 放假后难得来一趟广州游玩,当然要吃遍广州各路美食小吃然后再到珠江新城看看远近闻名的小蛮腰啦!可当小 Z 一路吃吃吃以后,天渐渐 ...

  3. 第01组 Alpha冲刺(2/6)

    队名:007 组长博客: https://www.cnblogs.com/Linrrui/p/11861798.html 作业博客: https://edu.cnblogs.com/campus/fz ...

  4. 使用GParted调整ubuntu根目录空间大小

    一.背景 Win10系统下安装ubuntu16.04双系统-常见问题解答 由于安装双系统时,ubuntu分区设置如下: 1) 主分区 ext4 / 30720MB 2) 主分区 swap area 8 ...

  5. vue中使用时间插件、vue使用laydate

    <input id="time1" readonly="readonly" placeholder="这里选择时间" v-model= ...

  6. SpringBoot——配置文件加载位置及外部配置加载顺序

    声明 本文部分转自:SpringBoot配置文件加载位置与优先级 正文 1. 项目内部配置文件 spring boot 启动会扫描以下位置的application.properties或者applic ...

  7. Kibana启动后外网访问不了

    问题 Kibana启动后,使用外网访问 http://ip地址:5601 访问不了日志中最后显示 "statusCode":302 ,在控制台 curl http://localh ...

  8. SQLite R*Tree 模块测试

    目录 SQLite R*Tree 模块测试 1.SQLite R*Tree 模块特性简介 2.SQLite R*Tree 模块简单测试代码 SQLite R*Tree 模块测试 相关参考: MySQL ...

  9. django中安全sql注入等

    模拟sql注入 使用原生sql语句编写login登录逻辑 class LoginUnsafeView(View): def get(self, request): return render(requ ...

  10. win10 搜索栏输入后长期没反应

    博客转载自:https://blog.csdn.net/qq_40875146/article/details/81742533 Get-AppXPackage -Name Microsoft.Win ...