在 Unix/Linux下 cp 用来复制文件 ,用法是  $ cp   source-file   target-file 

一. 函数介绍

1. 创建/重写文件 creat

#include<fcntl.h>

int  fd = creat(const char * pathname, mode_t mode);

如果文件不存在,就创建它 。如果存在就把它的内容清空 ,把文件长度设为 0 。

2. 写文件 write

#include <unistd.h>

ssize_t result = write( int fd , void *buf , size_t amt);

write这个系统调用告诉内核将内存中指定的数据写入文件,如果不能写入或写入失败,返回-1;如果写入成功,返回写入的字节数。

注意:调用 write 后要检查返回值是否与要写入的相同

3. 得到文件信息 stat

stat可用来获取文件的权限 (man 2 stat 察看),stat 结构体如下:

其中: st_mode 即是文件的权限

           struct stat {
               dev_t     st_dev;     /* ID of device containing file */
               ino_t     st_ino;     /* inode number */
               mode_t    st_mode;    /* protection */
               nlink_t   st_nlink;   /* number of hard links */
               uid_t     st_uid;     /* user ID of owner */
               gid_t     st_gid;     /* group ID of owner */
               dev_t     st_rdev;    /* device ID (if special file) */
               off_t     st_size;    /* total size, in bytes */
               blksize_t st_blksize; /* blocksize for file system I/O */
               blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
               time_t    st_atime;   /* time of last access */
               time_t    st_mtime;   /* time of last modification */
               time_t    st_ctime;   /* time of last status change */
           };


二.标准版本代码实现(版本一)

#include <stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<string.h>
#define BUFFERSIZE 4096

void oops(char * , char *);
int main(int ac , char *av[])
{
	int   in_fd , out_fd , n_chars;
	char  buf[BUFFERSIZE];
	struct stat sb;

	if( ac != 3)
	{
		fprintf(stderr,"usage: %s source destination \n",*av);
		exit(1);
	}
	/*
	 *   如果 原文件 与 目标文件相同时
	 */
	if ( strcmp(av[1], av[2]) == 0 ){
		fprintf(stderr,"cp: `%s' and `%s' are the same file.\n",
			av[1], av[2]);
		exit(1);
	}
	//  打开要复制的源文件
	if((in_fd = open(av[1],O_RDONLY)) == -1)
		oops("Can not open",av[1]);
	/*
	 * stat函数可以获得文件的权限
	 */
	if(stat(av[1] , &sb ) == -1)
	{
		perror("stat");
		exit(1);
	}
	// 创建要复制到的目的文件
	if((out_fd = creat(av[2],sb.st_mode)) == -1)
		oops("Can not creat ",av[2]);

	while(( n_chars = read(in_fd , buf ,BUFFERSIZE )) > 0)
		if(write( out_fd , buf , n_chars ) != n_chars)
			oops("Write error to ",av[2]);
	// 检查返回值是否与要写入的文件相同
	if( n_chars == -1)
		oops("Read error from ",av[1]);
	if( close(in_fd) == -1 || close(out_fd) == -1)
		oops("Error closing files ","");
	return 0;
}
void oops(char *s1 , char *s2)
{
	fprintf(stderr,"Error: %s ",s1);
	perror(s2);
	exit(1);
}

三.具有 -i 的代码实现(版本二)

        标准的cp 命令会自动覆盖已经存在的文件,而不会给出任何提示。现在要实现 cp 的参数 -i ,即可以在覆盖前给出提示,得到确认才覆盖。

 

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

#define BUFFERSIZE      4096

void  oops(char *, char *);
void  usage();
int   exists(char *filename);
int   ok_to_replace(char *filename);

int main(int ac, char *av[])
{
	int     in_fd, out_fd, n_chars;
    char    buf[BUFFERSIZE];
	char	*src = NULL, *dest = NULL;
	int	    i_option = 0;
	struct  stat   sb;
	// 检查参数
	while( --ac )
	{
		if ( strcmp("-i", *++av) == 0 )
			i_option = 1;
		else if ( src == NULL)
			src = *av;
		else if ( dest == NULL )
			dest = *av;
		else
			usage();
    }
	if ( src == NULL || dest == NULL )
		usage();
	if ( (in_fd=open(src, O_RDONLY)) == -1 )
		oops("Cannot open ", src );
	if(stat(src,&sb) == -1)
	{
		perror("stat");
		exit(1);
	}
	/*
	 * 当原文件src存在时,且 i_option== 1 ,即参数有  -i ;以及存在目标文件
	 */
	if ( i_option != 0 && exists(dest) != -1  )
	{
		//   如果按下的是 n,则不复制,直接退出
		if( !ok_to_replace(dest))
			exit(-1);
	}
	if ( (out_fd=creat( dest, sb.st_mode)) == -1 )
		oops("Cannot creat", dest);
	//  复制文件
	while ( (n_chars = read(in_fd , buf, BUFFERSIZE)) > 0 )
    	if ( write( out_fd, buf, n_chars ) != n_chars )
    		oops("Write error to ", dest);

	if ( n_chars == -1 )
		oops("Read error from ", src);
    if ( close(in_fd) == -1 || close(out_fd) == -1 )
    	oops("Error closing files","");
    return 0;
}
void oops(char *s1, char *s2)
{
	fprintf(stderr,"Error: %s ", s1);
	perror(s2);
	exit(1);
}
void usage()
{
	fprintf(stderr,"usage: cp [-i] source dest\n");
	exit(1);
}
/*
 * exists用于判断文件是否存在
 */
int exists(char *filename)
{
	int	fd = -1;
	if ( (fd = open(filename, O_RDONLY)) )
		close(fd);
	return  fd ;
}
/*
 * ok_to_replace 用于显示错误及从stdin中读取数据
 */
int ok_to_replace(char *filename)
{
	char	ans[10];	//  用于保存字符 y / n
	char	c;
	int	retval = 0;

	fprintf(stderr,"cp: Ok to replace `%s'? ", filename);
	if ( scanf("%9s", ans) == 1 )
	{
		if ( *ans == 'y' || *ans == 'Y' )
			retval = 1;
	}
	//消除掉 y 或者 n 后面的字符
	while( ( c = getchar() ) != EOF && c != '\n' )
		;
	return retval;
}












Logo

更多推荐