• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C语言 > Windows系统下使用C语言编写单线程的文件备份程序

Windows系统下使用C语言编写单线程的文件备份程序

作者: 字体:[增加 减小] 来源:互联网 时间:2017-05-28

通过本文主要向大家介绍了windows多线程编程,windows多线程,windows线程,windows 线程池,windows线程同步等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

写在最前方

源路径:即 From-Path,你准备要备份的资料
目的路径: 即 To-Path,你准备要存储备份的资料的地方
稍微回想一下,上一次写的代码,本次的任务是遍历目录及其子目录,那么这回要干的就是将上次遍历过的数据,挪一下窝,到我们想要他们去的位置。
这涉及到两个操作,遍历 和 拷贝,前一个动作我们在上一回已经实现了,只需做小小的改动,就能够使用。后一个动作也是需要靠 Windows API来完成,至于哪些,稍后再提。
现在先让我们完成一个魔法,3, 2, 1!:

 do{
   puts("-------------------------------------------------");
   fprintf(stdout, "The Default Path is : %s \n", DEFAULT_TO_PATH);
   fprintf(stdout, "Now The Path is   : %s \n", get_backup_topath());
   puts("-------------------------------------------------");
   puts("That is a System Back Up Software for Windows! ");
   puts("List of the software function : ");
   puts("1. Back Up ");
   puts("2. Set Back Up TO-PATH ");
   puts("3. Show TO-PATH History");
   puts("4. Read Me ");
   puts("5. Exit ");
   puts("-------------------------------------------------");
</div>

对界面稍微有了一些改动。

新增了第三行和第四行的 系统默认目的路径和当前使用的目的路径。

新增了倒数第四行的查看目的路径历史纪录的功能。

在main函数外头需要 extern DEFAULT_TO_PATH;因为引用了setPath.c里的一个全局变量。

写在中间

我们曾经提到要让函数的功能更加清晰,为了达到这个目的,应该把可能用到的一些原生库函数包裹一下,让可能发生的错误尽量掌握在我们自己的手里

安全函数

新建 safeFunc.h safeFunc.c
考虑一下我们需要包裹的函数: malloc, free, fopen 三个库函数。

为了不让后方的多线程实现产生更多的以后,不单独使用全局错误输出。
让我来将他们实现一下
我不会省略一些看似不必要的东西,例如注释,而是完整的呈现出来,如果觉得篇幅过长,可以选择跳跃的阅读。
魔法来了,3, 2, 1!

  

  #include <stdio.h> /* size_t */
   #include <stdlib.h>
   #include <setjmp.h>
   #define TRY_TIMES 3

   typedef struct _input_para{
     char * file; /* 待打开或创建的文件名 */
     char * mode; /* 打开的模式 */
   }params;

   jmp_buf malc_jmp; /*Malloc_s*/
   jmp_buf fopn_jmp; /*Fopen*/

   /**
    * @version 1.0 2015/10/01
    * @author wushengixin
    * @param  ... 参看结构体说明
         可传入任意的个数的,形式为 .file = "xxx", .mode = "x" 的参数
    * function 用于使用默认参数,并调用函数 Fopen 进行打开操作
    */
   #define Fopen_s(...) Fopen((params){.file = NULL, .mode = "r", __VA_ARGS__})
   FILE* Fopen(const params file_open);

   /**
    * @version 1.0 2015/10/01
    * @author wushengxin
    * param  sizes 输入需要分配的大小
    * function 用于隐藏一些对错误的处理,并调用malloc库函数分配空间
    */
   void * Malloc_s(size_t sizes);

   /**
    * @version 1.0 2015/10/01
    * @author wushengxin
    * @param  input 外部传入的等待释放的指针
    * function 用于隐藏一些对错误的处理,并调用free库函数进行释放指针
    */
   void Free_s(void * input);

</div>

里面用到了一些新的特性,如果使用 GCC/Clang作为编译器的,记得要开启-std=c11 支持。

  这几个函数就不再详细解释,而是简略说几个,接下来放上实现代码:

   FILE* Fopen(const params file_open)
   {
     int times = 0;
     FILE* ret_p = NULL;
     if (file_open.file == NULL)
     {
       fputs("The File Name is EMPTY! Comfirm it and Try Again", stderr);
       return ret_p;
     }
     setjmp(fopn_jmp); /* fopn_jmp To there */
     ret_p = fopen(file_open.file, file_open.mode);
     if (ret_p == NULL)
     {
       if (times++ < TRY_TIMES) 
       longjmp(fopn_jmp, 0); /* fopn_jmp From here */
       fprintf(stderr, "The File : %s Open with Mode (%s) Fail!\n", file_open.file, file_open.mode);
     }
     return ret_p;
   }

   void * Malloc_s(size_t sizes)
   {
     int times = 0;
     void * ret_p = NULL;
     if (sizes == 0)
       return NULL;
     setjmp(malc_jmp); /* malc_jmp To There */
     ret_p = malloc(sizes);
     if (ret_p == NULL)
     {
       if (times++ < TRY_TIMES) /* malc_jmp From Here */
         longjmp(malc_jmp, 0);
       fputs("Allocate Memory Fail!", stderr);
     }
     return ret_p;
   }

   void Free_s(void * input)
   {
     if (input == NULL)
     {
   #if !defined(NOT_DEBUG_AT_ALL)
       fputs("Sent A NULL pointer to the Free_s Function!", stderr);
   #endif
       return;
     }
     free(input);
     input = NULL;
   }

</div>

  第一个函数是用外部定义的宏 `Fopen_s`启动它,这里没有实现隐藏它。

  最后一个函数中使用了预处理的机制,如果在头文件中定义了 `#define NOT_DEBUG_AT_ALL`,这个输出将不在出现
安全函数已经撰写完成,接下来就是干正事了

setPath.h

我们首先要将程序里保存上默认的目的路径,首先想到用常量#define ...
其次应该要确保当前目的路径不被其他非法的渠道访问,那就应该用一个static 字符数组存储。
接下来就是要提供一个函数当作接口(这里用了接口这个术语不知道合不合适),来获取当前实际在使用的目的路径 get_backup_topath。
这里还需要将之前实现过的 repl_str ,再次实现一次,因为之前的显示功能只是测试,并不会实际应用到程序当中。
完成这两个功能函数以后,再去考虑实现怎么样设置路径,存储路径,以及使用文件流操作来缓存历史目的路径

   #include "safeFunc.h"

   #define SELF_LOAD_DEFAULT_PATH "C:/"
   #define MIN_PATH_NAME _MAX_PATH /* 最小的限制 */
   #define LARGEST_PATH_NAME 32767 /* 路径的最大限制 */

   /*
    * @version 1.0 2015/10/02
    * @author  wushengxin
    * @function 用于返回当前使用的目的路径
    */
   const char * get_backup_topath();

   /**
   * @version 1.0 2015/09/28
   * @author wushengxin
   * @param  src 外部传入的,用于调整
   * @function 用于替换路径中的 / 为 \ 的
   */
   void repl_str(char * src);

</div>

  对应的实现中,会定义一个静态的字符数组,且在头文件中能够看见,很多是在`showFiles`里定义过的。

  定义过的函数,例如 `repl_str`需要把`showFiles.c`中的**实现**,使用`#if 0 ... #endif` 进行注释掉,不然会发生重定义的错误。
setPath.c

   #include "setPath.h"

   static char to_path_buf[LARGEST_PATH_NAME] = SELF_LOAD_DEFAULT_PATH;
   const char * DEFAULT_TO_PATH = SELF_LOAD_DEFAULT_PATH;
   const int LARGEST_PATH = LARGEST_PATH_NAME;

   const char * get_backup_topath()
   {
     return to_path_buf;
   }

   void repl_str(char * src)
   {
     size_t length = strlen(src);
     for (size_t i = 0; i <= length; ++i)
     {
       if (src[i] == '/')
         src[i] = '\\';
     }
     return;
   }

</div>

有了上面的代码,主界面就再次能够无误运行了,那么剩下的就是实现,设置目的路径,存储目的路径到本地,显示目的路径,分别对应主界面的2, 3。
怎么实现比较好,再开始之前,分析一下会遇到的情况:
我们在得到目的路径之后,会将其拷贝给默认路径 to_path_buf,并且将其存储到本地缓存文件中,以便下次程序开始时可以直接使用上一次的路径
还可以使用另一个文件存储所有用过的历史路径,包含时间信息。
那么这就要求我们首先实现存储目的路径的功能,其次再实现设置目的路径的功能,最后实现显示目的路径的功能
注:两个看似无用的全局变量(const)是为了其他文件的可见性而设立的,且相对于#define能够省一些无足轻重的空间。

存储目的路径 store_hist_path

setPath.h

    #include <time.h>
    /**
     * @version 1.0 2015/10/02
     * @version wushengxin
     * @param  path 需要存储的路径
     * @function 用于存储路径到本地文件 "show_hist" 和 "use_hist" 
     */
    void store_hist_path(const char * path);
setPath.c

    void store_hist_path(const char * path)
 



 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • Windows系统下使用C语言编写单线程的文件备份程序

相关文章

  • 2017-05-28C++ 继承详解及实例代码
  • 2017-05-28学好C++必须做到的50条 绝对经典!
  • 2017-05-28c语言调用汇编的方法
  • 2017-05-28.h和.cpp文件的区别(zt)详细介绍
  • 2017-05-28一道超经典的C++结构体的题目
  • 2017-05-28高效实现整型数字转字符串int2str的方法
  • 2017-05-28C++ 异常处理 catch(...)介绍
  • 2017-05-28解析C语言中位字段内存分配的问题
  • 2017-05-28Visual C++中Tab View的多种实现方法
  • 2017-05-28C语言数据结构中二分查找递归非递归实现并分析

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • 用C语言判断字符是否为空白字符或特殊字符的方法
    • 关于C语言指针赋值的问题详解
    • C++利用MySQL API连接和操作数据库实例详解
    • 深入C/C++浮点数在内存中的存储方式详解
    • C++11的新特性简单汇总介绍 (一)
    • C语言入门的一些基本资源推荐和程序语法概览
    • 关于c语言的一个小bug详解
    • 基于errno返回值的对应错误码的详细介绍
    • C语言实现在windows服务中新建进程的方法
    • C/C++获取目录下的文件列表信息

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有