Project2: 文件夹同步工具
description
Transcript of Project2: 文件夹同步工具
Project2:文件夹同步工具
任务背景• 有 2 个文件夹 A 和 B ,经过之前的同步操作,
文件夹 B 中的内容与文件夹 A 中内容完全一致,现在用户对 A 文件夹中部分文件进行了编辑、移动、删除或者新增的操作,请你的程序根据文件夹 A 中的内容变化对文件夹 B进行增量更新。
功能要求• 文件夹 A 中保持不变的文件在文件夹 B 中保持不变,不更
新。
• 给出文件夹 A 中文件的更新情况列表,即列出与上次同步后文件夹 A 中所有发生变化的文件列表,包括• a) 与上次更新相比,所有新增文件的列表• b) 与上次更新相比,所有删除文件的列表• c) 与上次更新相比,所有发生变动的文件的列表
• 只对文件夹 A 中发生变化的文件在文件夹 B 中更新,即针对上述 3 中变化的文件,删除文件夹 B 中的相应原文件,并将 A 中最新文件复制到文件夹 B 中。• 注意:删除时需要提示用户是否确定删除源文件。
其他要求• 简单易用、界面友好
• 足够的提示信息• 输入错误的处理
• 更新速度快
满分: 85分
提高要求• 将上述工具移植到 windows 平台下。
• 在文件夹 B 中保留更新前的文件(比如,重新以特定的命名方式命名或者保存在特定的文件夹中的方式)。
• 开发图形界面
满分: 100
解题思路• 简单想法:
• 遍历文件夹 A 、 B ,对于 A 中的任一文件 f1, 在 B 中查找与 f1 同名文件 f2• 如果找到 f2 ,读取 f1 和 f2 的文件信息是否一
致• 一致:表示文件没有发生变化,什么也不做• 不一致:用 f1 覆盖 f2
• 如果没有找到,表示该文件是新文件,则将其复制到文件夹 B 中
• 还有没有其他问题?
实现细节• 如何遍历整个文件夹?
• Linux 命令• ls –R• Find
• 调用操作系统提供 API( 应用编程接口 )• opendir() 、 readdir() 、 closedir()
• 如何读取文件信息?• Linux 相关命令:• 系统函数:
问题 1 :遍历得到目录下所有的文件
• 方法 1 :利用 linux 命令的结果
• ls –R
• find
ls -R
find 命令• find 是 linux 中最有用的命令之一
• 用于在一个目录(及子目录)中搜索文件
• 可以指定一些匹配条件,如按文件名、文件类型、用户甚至是时间戳查找文件
• 举例:• find . -name "*.c”
• 在当前目录及其子目录中查找任何扩展名为 c 的文件• find . -type f
• 查找当前目录中的每一个普通文件• find / -mtime -5
• 在系统根目录下查找更改时间在 5 日以内的文件
如何在程序中利用 linux 命令的结果
• system() 函数:调用“ /bin/sh -c command” 执行特定的命令,阻塞当前进程直到 command 命令执行完毕
• 如何得到命令执行的结果
• system 的返回值不能待会命令的执行结果
• 输入输出重定向
原型:int system(const char *command);
返回值:如果无法启动 shell 运行命令, system 将返回 127 ;
出现不能执行 system 调用的其他错误时返回 -1 。如果 system能够顺利执行,返回那个命令的退出码。
输入输出重定向• Linux 重定向是指对原来系统命令的默认执行方式进行改变
• < 和 > 实现输出输入的重定向• 使用 < 或 > 时,相当于使用 0< 或 1>
• 简单举例• cmd > file
• 把 cmd 命令的输出重定向到文件 file 中。如果 file 已经存在,则清空原有文件,例如: ls -l >filenames.txt
• cmd < file• 使 cmd 命令从 file 读入
Linux 的管道• ls -l | wc -l
方法 1 :实现提示
• 在你的程序中,利用 system 函数得到目录下的所有文件,并将结果保存到文件中
• system(“find . > filelist.txt”);• system(“ls -l –R > filelist1.txt”);
方法 2 :利用操作系统提供的API
• 目录操作相关的 API• opendir
• 打开目录,并返回 DIR* 形态的目录流,接下来对目录的读取和搜索都要使用此返回值。
• readdir• 读取目录• 返回一个代表目录里下一个项目的指针
• closedir• 关闭目录
opendir :打开目录• 表头文件
#include<sys/types.h>#include<dirent.h>
• 定义函数DIR * opendir(const char * name);
• 函数说明opendir() 用来打开参数 name 指定的目录,
并返回 DIR* 形态的目录流,接下来对目录的读取和搜索都要使用此返回值。• 返回值
成功则返回 DIR* 型态的目录流,打开失败则返回 NULL 。
readdir 函数• 表头文件• #include<sys/types.h>• #include<dirent.h>
• 函数原型• struct dirent * readdir(DIR * dir);
• 函数说明• 返回一个代表目录 dirp 里下一个项目的指向 dirent 结构的
指针。如果到达目录流结尾或出错它返回 NULL 。
• 返回值• 成功则返回下个目录进入点。有错误发生或读取到目录文件尾
则返回 NULL 。
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]; /* 文件名 */};
closedir: 关闭目录
表头文件#include<sys/types.h>#include<dirent.h>
定义函数int closedir(DIR *dir);
函数说明closedir() 关闭参数 dir 所指的目录流。
返回值关闭成功则返回 0 ,失败返回 -1 ,错误
原因存于 errno 中。
编程提示pDir=opendir(path)
while( (ent=readdir(pDir))!=NULL )
{
//do something;
}
closedir(pDir);
问题 2 :如何确定文件是否更新过?
• Linux 文件的时间信息
• 如何读取文件信息?• Linux 相关命令: stat• 系统函数:
• stat() 、 fstat() 、 lstat()
Linux 中文件时间• 访问时间
• 修改时间
• 状态改变时间• 该文件最后一次被修改的时间• 通过 chmod 、 chown 命令修改一次文件属性,这个时间就会更新。
Windows 下:• 创建时间• 修改时间• 访问时间
如何获取文件信息• Linux 相关命令: stat
• 系统函数:• stat() 、 fstat() 、 lstat()
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; /* 最后状态改变时间 */ };
代码分析:遍历目录
#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; }
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);}
int main(int argc, char* argv[]){ if(argc == 2) { List( argv[1], 2 ); } else {
char *s = "."; List( s, 2 );
}
return 0;}
其他问题• 提高效率
• 可以将文件信息保存起来
• 移植到 windows 平台• linux 下的 API换成windows 平台的响应
API