30
Project2: 文文文文文文文

Project2: 文件夹同步工具

  • Upload
    chapa

  • View
    136

  • Download
    2

Embed Size (px)

DESCRIPTION

Project2: 文件夹同步工具. 任务 背景. 有 2 个文件夹 A 和 B ,经过之前的同步操作,文件夹 B 中的内容与文件夹 A 中内容完全一致,现在用户对 A 文件夹中部分文件进行了编辑、移动、删除或者新增的操作,请你的程序根据文件夹 A 中的内容变化对文件夹 B 进行增量更新。. 功能要求. 文件夹 A 中保持不变的文件在文件夹 B 中保持不变,不更新。 给出文件夹 A 中文件的更新情况列表,即列出与上次同步后文件夹 A 中所有发生变化的文件列表, 包括 a ) 与上次更新相比,所有新增文 件的列表 b ) 与上次更新相比,所有删除文 件的列表 - PowerPoint PPT Presentation

Citation preview

Page 1: Project2: 文件夹同步工具

Project2:文件夹同步工具

Page 2: Project2: 文件夹同步工具

任务背景• 有 2 个文件夹 A 和 B ,经过之前的同步操作,

文件夹 B 中的内容与文件夹 A 中内容完全一致,现在用户对 A 文件夹中部分文件进行了编辑、移动、删除或者新增的操作,请你的程序根据文件夹 A 中的内容变化对文件夹 B进行增量更新。

Page 3: Project2: 文件夹同步工具

功能要求• 文件夹 A 中保持不变的文件在文件夹 B 中保持不变,不更

新。

• 给出文件夹 A 中文件的更新情况列表,即列出与上次同步后文件夹 A 中所有发生变化的文件列表,包括• a) 与上次更新相比,所有新增文件的列表• b) 与上次更新相比,所有删除文件的列表• c) 与上次更新相比,所有发生变动的文件的列表

• 只对文件夹 A 中发生变化的文件在文件夹 B 中更新,即针对上述 3 中变化的文件,删除文件夹 B 中的相应原文件,并将 A 中最新文件复制到文件夹 B 中。• 注意:删除时需要提示用户是否确定删除源文件。

Page 4: Project2: 文件夹同步工具

其他要求• 简单易用、界面友好

• 足够的提示信息• 输入错误的处理

• 更新速度快

满分: 85分

Page 5: Project2: 文件夹同步工具

提高要求• 将上述工具移植到 windows 平台下。

• 在文件夹 B 中保留更新前的文件(比如,重新以特定的命名方式命名或者保存在特定的文件夹中的方式)。

• 开发图形界面

满分: 100

Page 6: Project2: 文件夹同步工具

解题思路• 简单想法:

• 遍历文件夹 A 、 B ,对于 A 中的任一文件 f1, 在 B 中查找与 f1 同名文件 f2• 如果找到 f2 ,读取 f1 和 f2 的文件信息是否一

致• 一致:表示文件没有发生变化,什么也不做• 不一致:用 f1 覆盖 f2

• 如果没有找到,表示该文件是新文件,则将其复制到文件夹 B 中

• 还有没有其他问题?

Page 7: Project2: 文件夹同步工具

实现细节• 如何遍历整个文件夹?

• Linux 命令• ls –R• Find

• 调用操作系统提供 API( 应用编程接口 )• opendir() 、 readdir() 、 closedir()

• 如何读取文件信息?• Linux 相关命令:• 系统函数:

Page 8: Project2: 文件夹同步工具

问题 1 :遍历得到目录下所有的文件

• 方法 1 :利用 linux 命令的结果

• ls –R

• find

Page 9: Project2: 文件夹同步工具

ls -R

Page 10: Project2: 文件夹同步工具

find 命令• find 是 linux 中最有用的命令之一

• 用于在一个目录(及子目录)中搜索文件

• 可以指定一些匹配条件,如按文件名、文件类型、用户甚至是时间戳查找文件

• 举例:• find . -name "*.c”

• 在当前目录及其子目录中查找任何扩展名为 c 的文件• find . -type f

• 查找当前目录中的每一个普通文件• find / -mtime -5

• 在系统根目录下查找更改时间在 5 日以内的文件

Page 11: Project2: 文件夹同步工具
Page 12: Project2: 文件夹同步工具

如何在程序中利用 linux 命令的结果

• system() 函数:调用“ /bin/sh -c command” 执行特定的命令,阻塞当前进程直到 command 命令执行完毕

• 如何得到命令执行的结果

• system 的返回值不能待会命令的执行结果

• 输入输出重定向

原型:int system(const char *command);

返回值:如果无法启动 shell 运行命令, system 将返回 127 ;

出现不能执行 system 调用的其他错误时返回 -1 。如果 system能够顺利执行,返回那个命令的退出码。

Page 13: Project2: 文件夹同步工具

输入输出重定向• Linux 重定向是指对原来系统命令的默认执行方式进行改变

• < 和 > 实现输出输入的重定向• 使用 < 或 > 时,相当于使用 0< 或 1>

• 简单举例• cmd > file

• 把 cmd 命令的输出重定向到文件 file 中。如果 file 已经存在,则清空原有文件,例如: ls -l >filenames.txt

• cmd < file• 使 cmd 命令从 file 读入

Page 14: Project2: 文件夹同步工具

Linux 的管道• ls -l | wc -l

Page 15: Project2: 文件夹同步工具

方法 1 :实现提示

• 在你的程序中,利用 system 函数得到目录下的所有文件,并将结果保存到文件中

• system(“find . > filelist.txt”);• system(“ls -l –R > filelist1.txt”);

Page 16: Project2: 文件夹同步工具

方法 2 :利用操作系统提供的API

• 目录操作相关的 API• opendir

• 打开目录,并返回 DIR* 形态的目录流,接下来对目录的读取和搜索都要使用此返回值。

• readdir• 读取目录• 返回一个代表目录里下一个项目的指针

• closedir• 关闭目录

Page 17: Project2: 文件夹同步工具

opendir :打开目录• 表头文件

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

• 定义函数DIR * opendir(const char * name);

• 函数说明opendir() 用来打开参数 name 指定的目录,

并返回 DIR* 形态的目录流,接下来对目录的读取和搜索都要使用此返回值。• 返回值

成功则返回 DIR* 型态的目录流,打开失败则返回 NULL 。

Page 18: Project2: 文件夹同步工具

readdir 函数• 表头文件• #include<sys/types.h>• #include<dirent.h>

• 函数原型• struct dirent * readdir(DIR * dir);

• 函数说明• 返回一个代表目录 dirp 里下一个项目的指向 dirent 结构的

指针。如果到达目录流结尾或出错它返回 NULL 。

• 返回值• 成功则返回下个目录进入点。有错误发生或读取到目录文件尾

则返回 NULL 。

Page 19: Project2: 文件夹同步工具

readdir 函数 (2)

在 Linux 系统里, dirent 结构定义如下:

struct dirent { ino_t d_ino; /* inode number */ off_t d_off; /* 下一个项目的偏移 */ unsigned short d_reclen; /* 本记录的长度 */ unsigned char d_type; /* 文件类型;不是被所有文件系统支持 */ char d_name[256]; /* 文件名 */};

Page 20: Project2: 文件夹同步工具

closedir: 关闭目录

表头文件#include<sys/types.h>#include<dirent.h>

定义函数int closedir(DIR *dir);

函数说明closedir() 关闭参数 dir 所指的目录流。

返回值关闭成功则返回 0 ,失败返回 -1 ,错误

原因存于 errno 中。

Page 21: Project2: 文件夹同步工具

编程提示pDir=opendir(path)

while( (ent=readdir(pDir))!=NULL )

{

//do something;

}

closedir(pDir);

Page 22: Project2: 文件夹同步工具
Page 23: Project2: 文件夹同步工具

问题 2 :如何确定文件是否更新过?

• Linux 文件的时间信息

• 如何读取文件信息?• Linux 相关命令: stat• 系统函数:

• stat() 、 fstat() 、 lstat()

Page 24: Project2: 文件夹同步工具

Linux 中文件时间• 访问时间

• 修改时间

• 状态改变时间• 该文件最后一次被修改的时间• 通过 chmod 、 chown 命令修改一次文件属性,这个时间就会更新。

Windows 下:• 创建时间• 修改时间• 访问时间

Page 25: Project2: 文件夹同步工具

如何获取文件信息• Linux 相关命令: stat

• 系统函数:• stat() 、 fstat() 、 lstat()

Page 26: Project2: 文件夹同步工具

lstat 函数• 返回与文件有关的信息结构

• int lstat(const char *path, struct stat *buf); struct stat { dev_t st_dev; /* 文件所在设备的标识 */ ino_t st_ino; /* 文件结点号 */ 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; /* 分配给文件的块的数量, 512字节为单元 */ time_t st_atime; /* 最后访问时间 */ time_t st_mtime; /* 最后修改时间 */ time_t st_ctime; /* 最后状态改变时间 */ };

Page 27: Project2: 文件夹同步工具

代码分析:遍历目录

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

void List( char *path, int indent ){ struct dirent* ent = NULL; DIR *pDir; char dir[512]; struct stat statbuf; if( (pDir=opendir(path))==NULL ) { fprintf( stderr, "Cannot open directory:%s\n", path ); return; }

Page 28: Project2: 文件夹同步工具

while( (ent=readdir(pDir))!=NULL ) { // 得到读取文件的绝对路径名 snprintf( dir, 512,"%s/%s", path, ent->d_name ); // 得到文件信息 lstat( dir, &statbuf); //判断是目录还是文件 if( S_ISDIR(statbuf.st_mode) ) { //排除当前目录和上级目录 if(strcmp( ".",ent->d_name) == 0 || strcmp( "..",ent->d_name) == 0) { continue; } // 如果是子目录 ,递归调用函数本身 , 实现子目录中文件遍历 printf( "%*s 子目录 :%s/\n", indent, "", ent->d_name ); //递归调用 , 遍历子目录中文件 List( dir, indent+4 ); } else { printf( "%*s 文件 :%s\n", indent, "", ent->d_name ); } } closedir(pDir);}

Page 29: Project2: 文件夹同步工具

int main(int argc, char* argv[]){ if(argc == 2) { List( argv[1], 2 ); } else {

char *s = "."; List( s, 2 );

}

return 0;}

Page 30: Project2: 文件夹同步工具

其他问题• 提高效率

• 可以将文件信息保存起来

• 移植到 windows 平台• linux 下的 API换成windows 平台的响应

API