OO编程实践之“同步文件夹”——实现(3)

这几天一直在看common lisp,我发现它比c++抽象层次高很多,编程开发速度极快。不过目前而言,c++还是前面比较有用的,毕竟目前桌面程序用的比较多。

回到正题,前2篇基本上已经将基本功能实现了。今天需要进行实际的文件操作。

前面Folder类的操作都是我故意模拟文件系统的,今天利用boost/filesystem库来实现。

面向对象的一个重要原则是开闭原则(OCP),我希望我不再Folder中直接修改,而是通过继承的方式来进行。

重构代码:

1. 更改Folder的类名为MockFolder

2. 新建Folder类,该类为虚基类,MockFolder继承它

3. 修改SynchronousSystem,让其依赖于Folder,而不是之前的MockFolder。

于是所有类代码如下:

类Folder

class Folder
{
public:
    Folder(const std::string& path):itsPath(path){}
    //info
    virtual FileModifyTime getFileModifyTime(const std::string& filename) =0;
    virtual bool isDirectory(const std::string& filename) = 0;
    virtual bool isExist(const std::string& filename) = 0;
    //operator
    virtual void backUp(const std::string& filename) = 0;
    virtual void copyFileTo(const std::string& filename, Folder* destFolder) = 0;
    
    virtual std::string getAbsoluteFilePath(const std::string& filename) const { return itsPath + "\\" + filename;}
    std::string getPath(){return itsPath;}
protected:
    std::string itsPath;
};

类SynchronousSystem

class SynchronousSystem
{
public:
    SynchronousSystem(MockFolder* source,MockFolder* dest):itsSourceFolder(source),itsDestFolder(dest){}
    bool isNeedUpdate(const std::string& filename)
    {
        if(!itsDestFolder->isExist(filename))
            return true;
        if(!itsSourceFolder->isDirectory(filename) && itsSourceFolder->getFileModifyTime(filename).isNewerThan(itsDestFolder->getFileModifyTime(filename)) )
            return true;
        return false;
    }
    void Synchronous(const std::string& filename)
    {
        if (isNeedUpdate(filename))
        {
            itsDestFolder->backUp(filename);
            itsSourceFolder->copyFileTo(filename,itsDestFolder);
        }
    }
private:
    Folder* itsSourceFolder;
    Folder* itsDestFolder;
};

类MockFolder

class MockFolder : public Folder
{
public:
    MockFolder(const std::string& path):Folder(path){}
    FileModifyTime getFileModifyTime(const std::string& filename)
    {
        if (filename == "FileSourceIsNew" && itsPath == "destFolder")
            return FileModifyTime(std::time(NULL)-1000);
        if (filename == "FileDestIsNew" && itsPath == "sourceFolder")
            return FileModifyTime(std::time(NULL)-1000);
        if (filename == "FolderExist" && itsPath == "destFolder")
            return FileModifyTime(std::time(NULL)-1000);
        return FileModifyTime(std::time(NULL));
    }
    bool isDirectory(const std::string& filename)
    {
        return (filename == "FolderNotExist" || filename == "FolderExist");
    }
    bool isExist(const std::string& filename)
    {
        if(filename == "FileNotExist" || filename == "FolderNotExist")
            return false;
        else
            return true;
    }

    //operator
    void backUp(const std::string& filename)
    {
        if(isExist(filename))
            std::cout << "Backup \""<< filename << "\"" << std::endl;
    }
    void copyFileTo(const std::string& filename, Folder* destFolder)
    {
        std::cout << "Copy File \"" << filename << "\"" << std::endl; 
    }
};

这样,效果与之前一致,但是Folder接口提取出来,SynchronousSystem不再依赖Folder的具体实现。

至此为至,我们只需要新建一个新类Win32Folder(继承自Folder)来实现文件操作就行。

额,忘了写测试了。

为了实验,我在F盘建了2个文件夹,分别是source和dest,我得构建一些文件和文件夹来做这个实验。

source文件夹中有:

SourceIsNew.txt
DestNotExist.txt
DestIsSameAsSource.txt
DestIsNew.txt
DestIsExist
    SourceIsNew.txt
    DestNotExist.txt
    DestIsSameAsSource.txt
    DestIsNew.txt
DestNotExist
    SourceIsNew.txt
    DestNotExist.txt
    DestIsSameAsSource.txt
    DestIsNew.txt

dest文件夹中有:

SourceIsNew.txt
DestIsSameAsSource.txt
DestIsNew.txt
DestIsExist
    SourceIsNew.txt
    DestIsSameAsSource.txt
    DestIsNew.txt

我其他目录中新建好这些文件,然后每次运行的拷贝过来就行,我的测试代码变为:

    //constructor
    remove_all(path("F:/source"));
    remove_all(path("F:/dest"));
    system("xcopy /E F:\\SynTest\\source F:\\source\\ >nul");
    system("xcopy /E F:\\SynTest\\dest F:\\dest\\ >nul");

    Win32Folder source("F:/source");
    Win32Folder dest("F:/dest");
    SynchronousSystem SS(&source,&dest);

    path sourcePath("F:/source");
    for (directory_iterator it = directory_iterator(sourcePath); it != directory_iterator(); ++it)
    {
        std::string filename = it->path().string();
        filename = filename.substr(sourcePath.string().length()+1);
        SS.Synchronous(filename);
    }

开始写Win32Folder的代码

class Win32Folder : public Folder
{
public:
    Win32Folder(const std::string& path): Folder(path){}
    //info
    FileModifyTime getFileModifyTime(const std::string& filename);
    bool isDirectory(const std::string& filename);
    bool isExist(const std::string& filename);
    //operator
    void backUp(const std::string& filename);
    void copyFileTo(const std::string& filename, Folder* destFolder);
};

他的实现为:

#include "Win32Folder.h"

#include <boost/filesystem.hpp>

using namespace boost::filesystem;

FileModifyTime Win32Folder::getFileModifyTime( const std::string& filename )
{
    return last_write_time(path(getAbsoluteFilePath(filename)));
}

bool Win32Folder::isDirectory( const std::string& filename )
{
    return is_directory(path(getAbsoluteFilePath(filename)));
}

bool Win32Folder::isExist( const std::string& filename )
{
    return exists(path(getAbsoluteFilePath(filename)));
}

void Win32Folder::backUp( const std::string& filename )
{
    path filePath(getAbsoluteFilePath(filename));
    std::string backFilePathString = filePath.parent_path().string() + "\\" + filePath.stem().string() + ".bak" + filePath.extension().string();
    path backFilePath(backFilePathString);
    if (exists(backFilePath))
        remove(backFilePath);
    rename(filePath,backFilePath);
}

void Win32Folder::copyFileTo( const std::string& filename, Folder* destFolder )
{
    path file(getAbsoluteFilePath(filename));
    path destFile(destFolder->getPath());
    destFile /= filename;
    copy(file,destFile);
}

好了,写到这里了。我开始生成,运行。

产生了一个异常错误:

boost::filesystem::rename: 系统找不到指定的文件。: "F:/dest\DestNotExist", "F:/dest\DestNotExist.bak"

怎么会产生这个错误呢,我在哪里调用rename函数呢。。。噢,在backUp函数中,我并没有检查它是否存在。这貌似告诉我上一篇疑问的问题,判断存在是在SynchronousSystem还是在Folder类中,现在貌似有了答案。

于是SynchronousSystem代码中的Synchronous代码变为:

    void Synchronous(const std::string& filename)
    {
        if (isNeedUpdate(filename))
        {
            if(itsDestFolder->isExist(filename))
                itsDestFolder->backUp(filename);
            itsSourceFolder->copyFileTo(filename,itsDestFolder);
        }
    }

继续执行,又出现一个错误:

boost::filesystem::copy_directory: 文件名、目录名或卷标语法不正确。: "F:/source\DestNotExist", "F:/source\DestNotExist"

这是因为在copy目录的时候使用boost/filesystem的copy函数,它调用copy_directory,这个copy_directory不会新建directory,因此得调用创建directory的函数,Win32Folder的copyFileTo得修改成这样:

void Win32Folder::copyFileTo( const std::string& filename, Folder* destFolder )
{
    path file(getAbsoluteFilePath(filename));
    path destFile(destFolder->getPath());
    destFile /= filename;
    if(is_directory(destFile))
        create_directory(destFile);
    else
        copy(file,destFile);
}

其实,这还没有验证他的正确行。下面将写验证代码。

    //check
    CPPUNIT_ASSERT(exists("F:/dest/DestNotExist.txt"));
    CPPUNIT_ASSERT(exists("F:/dest/SourceIsNew.bak.txt"));
    CPPUNIT_ASSERT(exists("F:/dest/DestNotExist"));
    CPPUNIT_ASSERT_EQUAL(last_write_time("F:/source/SourceIsNew.txt"),last_write_time("F:/dest/SourceIsNew.txt"));

测试通过了。

原文地址:https://www.cnblogs.com/zhangyonghugo/p/2575283.html