亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Windows系統(tǒng)下使用C語言編寫單線程的文件備份程序

 更新時(shí)間:2016年02月16日 14:24:53   投稿:goldensun  
這篇文章主要介紹了Windows系統(tǒng)下使用C語言編寫單線程的文件備份程序,文中給出了實(shí)現(xiàn)的幾個(gè)關(guān)鍵代碼片段,剩下的只要套上main和線程調(diào)用的相關(guān)函數(shù)即可,非常詳細(xì),需要的朋友可以參考下

寫在最前方

源路徑:即 From-Path,你準(zhǔn)備要備份的資料
目的路徑: 即 To-Path,你準(zhǔn)備要存儲備份的資料的地方
稍微回想一下,上一次寫的代碼,本次的任務(wù)是遍歷目錄及其子目錄,那么這回要干的就是將上次遍歷過的數(shù)據(jù),挪一下窩,到我們想要他們?nèi)サ奈恢谩?br /> 這涉及到兩個(gè)操作,遍歷 和 拷貝,前一個(gè)動作我們在上一回已經(jīng)實(shí)現(xiàn)了,只需做小小的改動,就能夠使用。后一個(gè)動作也是需要靠 Windows API來完成,至于哪些,稍后再提。
現(xiàn)在先讓我們完成一個(gè)魔法,3, 2, 1?。?/p>

 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("-------------------------------------------------");

對界面稍微有了一些改動。

新增了第三行和第四行的 系統(tǒng)默認(rèn)目的路徑和當(dāng)前使用的目的路徑。

新增了倒數(shù)第四行的查看目的路徑歷史紀(jì)錄的功能。

在main函數(shù)外頭需要 extern DEFAULT_TO_PATH;因?yàn)橐昧藄etPath.c里的一個(gè)全局變量。

寫在中間

我們曾經(jīng)提到要讓函數(shù)的功能更加清晰,為了達(dá)到這個(gè)目的,應(yīng)該把可能用到的一些原生庫函數(shù)包裹一下,讓可能發(fā)生的錯(cuò)誤盡量掌握在我們自己的手里

安全函數(shù)

新建 safeFunc.h safeFunc.c
考慮一下我們需要包裹的函數(shù): malloc, free, fopen 三個(gè)庫函數(shù)。

為了不讓后方的多線程實(shí)現(xiàn)產(chǎn)生更多的以后,不單獨(dú)使用全局錯(cuò)誤輸出。
讓我來將他們實(shí)現(xiàn)一下
我不會省略一些看似不必要的東西,例如注釋,而是完整的呈現(xiàn)出來,如果覺得篇幅過長,可以選擇跳躍的閱讀。
魔法來了,3, 2, 1!

  

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

   typedef struct _input_para{
     char * file; /* 待打開或創(chuàng)建的文件名 */
     char * mode; /* 打開的模式 */
   }params;

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

   /**
    * @version 1.0 2015/10/01
    * @author wushengixin
    * @param  ... 參看結(jié)構(gòu)體說明
         可傳入任意的個(gè)數(shù)的,形式為 .file = "xxx", .mode = "x" 的參數(shù)
    * function 用于使用默認(rèn)參數(shù),并調(diào)用函數(shù) Fopen 進(jìn)行打開操作
    */
   #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 用于隱藏一些對錯(cuò)誤的處理,并調(diào)用malloc庫函數(shù)分配空間
    */
   void * Malloc_s(size_t sizes);

   /**
    * @version 1.0 2015/10/01
    * @author wushengxin
    * @param  input 外部傳入的等待釋放的指針
    * function 用于隱藏一些對錯(cuò)誤的處理,并調(diào)用free庫函數(shù)進(jìn)行釋放指針
    */
   void Free_s(void * input);

里面用到了一些新的特性,如果使用 GCC/Clang作為編譯器的,記得要開啟-std=c11 支持。

  這幾個(gè)函數(shù)就不再詳細(xì)解釋,而是簡略說幾個(gè),接下來放上實(shí)現(xiàn)代碼:

   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;
   }

  第一個(gè)函數(shù)是用外部定義的宏 `Fopen_s`啟動它,這里沒有實(shí)現(xiàn)隱藏它。

  最后一個(gè)函數(shù)中使用了預(yù)處理的機(jī)制,如果在頭文件中定義了 `#define NOT_DEBUG_AT_ALL`,這個(gè)輸出將不在出現(xiàn)
安全函數(shù)已經(jīng)撰寫完成,接下來就是干正事了

setPath.h

我們首先要將程序里保存上默認(rèn)的目的路徑,首先想到用常量#define ...
其次應(yīng)該要確保當(dāng)前目的路徑不被其他非法的渠道訪問,那就應(yīng)該用一個(gè)static 字符數(shù)組存儲。
接下來就是要提供一個(gè)函數(shù)當(dāng)作接口(這里用了接口這個(gè)術(shù)語不知道合不合適),來獲取當(dāng)前實(shí)際在使用的目的路徑 get_backup_topath。
這里還需要將之前實(shí)現(xiàn)過的 repl_str ,再次實(shí)現(xiàn)一次,因?yàn)橹暗娘@示功能只是測試,并不會實(shí)際應(yīng)用到程序當(dāng)中。
完成這兩個(gè)功能函數(shù)以后,再去考慮實(shí)現(xiàn)怎么樣設(shè)置路徑,存儲路徑,以及使用文件流操作來緩存歷史目的路徑

   #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 用于返回當(dāng)前使用的目的路徑
    */
   const char * get_backup_topath();

   /**
   * @version 1.0 2015/09/28
   * @author wushengxin
   * @param  src 外部傳入的,用于調(diào)整
   * @function 用于替換路徑中的 / 為 \ 的
   */
   void repl_str(char * src);

  對應(yīng)的實(shí)現(xiàn)中,會定義一個(gè)靜態(tài)的字符數(shù)組,且在頭文件中能夠看見,很多是在`showFiles`里定義過的。

  定義過的函數(shù),例如 `repl_str`需要把`showFiles.c`中的**實(shí)現(xiàn)**,使用`#if 0 ... #endif` 進(jìn)行注釋掉,不然會發(fā)生重定義的錯(cuò)誤。
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;
   }

有了上面的代碼,主界面就再次能夠無誤運(yùn)行了,那么剩下的就是實(shí)現(xiàn),設(shè)置目的路徑,存儲目的路徑到本地,顯示目的路徑,分別對應(yīng)主界面的2, 3。
怎么實(shí)現(xiàn)比較好,再開始之前,分析一下會遇到的情況:
我們在得到目的路徑之后,會將其拷貝給默認(rèn)路徑 to_path_buf,并且將其存儲到本地緩存文件中,以便下次程序開始時(shí)可以直接使用上一次的路徑
還可以使用另一個(gè)文件存儲所有用過的歷史路徑,包含時(shí)間信息。
那么這就要求我們首先實(shí)現(xiàn)存儲目的路徑的功能,其次再實(shí)現(xiàn)設(shè)置目的路徑的功能,最后實(shí)現(xiàn)顯示目的路徑的功能
注:兩個(gè)看似無用的全局變量(const)是為了其他文件的可見性而設(shè)立的,且相對于#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)
    {
      time_t ctimes; 
      time(&ctimes); /* 獲取時(shí)間 */
      FILE* input_use = Fopen_s(.file = "LastPath.conf", .mode = "w"); /* 每次寫入覆蓋 */
      FILE* input_show = Fopen_s(.file = "PathHistory.txt", .mode = "a");
      if (!input_show || !input_use)
      {
    #if !defined(NOT_DEBUG_AT_ALL)
        fputs("Open/Create the File Fail!", stderr);
    #endif
        return;
      }
      fprintf(input_use, "%s\n", path); /* 寫入 */
      fprintf(input_show, "%s %s", path, ctime(&ctimes));
      fclose(input_show);
      fclose(input_use);
      return;
    }

    `time`和`ctime` 函數(shù)的使用網(wǎng)路上的介紹更加全面,這里不做解釋。

    完成了存儲的函數(shù)之后,便是實(shí)現(xiàn)從鍵盤讀取并且設(shè)置默認(rèn)路徑
設(shè)置目的路徑 set_enter_path

在此處需要停下來在此思考一下,如果用戶輸入了錯(cuò)誤的路徑(無效路徑或者惡意路徑),也應(yīng)該被讀取嗎?所以應(yīng)該增加一個(gè)檢查,用于確認(rèn)路徑的有效性。
setPath.h

    #include <string.h>
    #include <io.h> /* _access */
    enum {NOT_EXIST = 0, EXIST = 1};
    /**
     * @version 1.0 2015/10/02
     * @author  wushengxin
     * @function 用于讀取從鍵盤輸入的路徑并將之設(shè)置為默認(rèn)路徑,并存儲。
     */
    void set_enter_path();

    /**
     * @version 1.0 2015/10/02
     * @author  wushengxin
     * @param  path 用于檢查的路徑
     * @function 用于檢查用戶輸入的路徑是否是有效的
     */
    int is_valid_path(const char * path);

setPath.c

    int is_valid_path(const char * path)
    {/* _access 后方有解釋 */
      if (_access(path, 0) == 0) /* 是否存在 */
        return EXIST;
      else
        return NOT_EXIST;
    }

    void set_enter_path()
    {
      int intJudge = 0; /* 用來判斷是否決定完成輸入 */
      char tmpBuf[LARGEST_PATH_NAME]; /** 臨時(shí)緩沖區(qū) **/
      while (1)
      {
        printf("Enter The Path You want!\n");
        fgets(tmpBuf, LARGEST_PATH_NAME*sizeof(char), stdin); /* 獲取輸入的路徑 */
        sscanf(tmpBuf, "%s", to_path_buf);
        if (is_valid_path(to_path_buf) == NOT_EXIST)
        {
          fprintf(stderr, "Your Enter is Empty, So Load the Default Path\n");
          fprintf(stderr, "%s \n", SELF_LOAD_DEFAULT_PATH);
          strcpy(to_path_buf, SELF_LOAD_DEFAULT_PATH);
        }
        fprintf(stdout, "Your Enter is \" %s \" ?(1 for yes, 0 for no) \n", to_path_buf);

        fgets(tmpBuf, LARGEST_PATH_NAME*sizeof(char), stdin);
        sscanf(tmpBuf, "%d", &intJudge); /* 獲取判斷數(shù)的輸入 */
        if (intJudge != 0)
        {
          if (to_path_buf[strlen(to_path_buf) - 1] != '/')
            strcat(to_path_buf, "/");/* 如果最后一個(gè)字符不是'/',則添加,這里沒考慮是否越界 */
          store_hist_path(to_path_buf);
          break;
        } /* if(intJudge) */
      }/* while (1) */
      return;
    }/* set_enter_path */

    這一組函數(shù)的功能稍微復(fù)雜,大體來說便是 `讀取路徑輸入->檢查路徑有效性->讀取判斷數(shù)->是否結(jié)束循環(huán)`

    其中`_access` 函數(shù)有些淵源,因?yàn)檫@個(gè)函數(shù)被大家所熟知的是這個(gè)形式 `access`,但由于這個(gè)形式是 **POSIX** 標(biāo)準(zhǔn),故 **Windows** 將其實(shí)現(xiàn)為`_access`,用法上還是一樣的,就是名字不同而已。
顯示歷史路徑 show_hist_path

setPath.h

    /**
     * @version 1.0 2015/10/02
     * author  wushengxin
     * function 用于在窗口顯示所有的歷史路徑
     */
    void show_hist_path();

setPath.c

    void show_hist_path()
    {
      system("cls");
      char outBufName[LARGEST_PATH_NAME] = {'\0'};
      FILE* reading = Fopen_s(.file = "PathHistory.txt", .mode = "r");
      if (!reading)
      return;

      for (int i = 1; i <= 10 && (!feof(reading)); ++i)  
      {
        fgets(outBufName, LARGEST_PATH_NAME*sizeof(char), reading);
        fprintf(stdout, "%2d. %s", i, outBufName);
      }
      fclose(reading);
      system("pause");
      return;
    }

剩下最后一個(gè)收尾工作

初始化路徑
每次程序啟動的時(shí)候,我們都會讀取本地文件,獲取上一次程序使用的最后一個(gè)路徑,作為當(dāng)前使用的目的路徑
初始化目的路徑 init_path

setPath.h

    /**
     * @versions 1.0 2015/10/02
     * @author  wushengxin
     * @function 用于每次程序啟動時(shí)初始化目的路徑
     */
    void init_path();

setPath.c

    void init_path()
    {
      int len = 0;
      char last_path[LARGEST_PATH_NAME] = { '\0' };
      FILE* hist_file = Fopen_s(.file = "LastPath.conf", .mode = "r");
      if (!hist_file) /* 打開失敗則不初始化 */
        return;
      fgets(last_path, LARGEST_PATH_NAME, hist_file);
      len = strlen(last_path);
      if (len > 1)
      {
        last_path[len - 1] = '\0'; /* 消除一個(gè)多余的 ‘\n' */
        strcpy(to_path_buf, last_path);
      }
      return;
    }

    這樣就大功告成了,對于這個(gè)函數(shù)中的后`8`行代碼,沒使用慣用的`fgets 配合 sscanf` 是因?yàn)槿绻@么干的話,需要搭配一個(gè)`memset`函數(shù)清零,后面會有解釋。

對于memset的解釋
這個(gè)函數(shù)對于大的內(nèi)存塊的初始化實(shí)際上是很慢的,當(dāng)然我們這個(gè)30KB左右大概的內(nèi)存可能影響還沒有那么大,但是上兆以后,調(diào)用memset就是一種性能問題了,很多情況下,編譯器在開啟高優(yōu)化等級之后會自動幫你取消memset的隱式調(diào)用
什么隱式調(diào)用,例如 init_path的第二行代碼,聲明并且用花括號初始化這個(gè)數(shù)組的時(shí)候,就會調(diào)用隱式memset。

寫在中間

上面完成了界面的大部分功能,剩下的便是備份這個(gè)主要功能。
在完成備份之前,首先想想要如何構(gòu)造這個(gè)備份模型

既然是備份,如果不想擴(kuò)展為多線程的形式,參考第一次寫的遍歷函數(shù)(show_structure)直接找到文件便調(diào)用Windows API(稍后介紹)進(jìn)行復(fù)制即可,不需要講待備份的文件路徑保存下來。
如果要考慮多線程擴(kuò)展,我們就需要從長計(jì)議。
對于一個(gè)備份模型,最好的莫過于使用一個(gè)隊(duì)列,依舊實(shí)行的是遍歷模式,但是將找到的文件路徑保存,并放入一個(gè)先進(jìn)先出的隊(duì)列中,這樣我們就能夠保證在擴(kuò)展成多線程的時(shí)候,可以有一個(gè)很清晰的模型參考。
那么現(xiàn)在的任務(wù)就是實(shí)現(xiàn)這個(gè)用于備份的隊(duì)列模型。
隊(duì)列模型

  • 應(yīng)該有一個(gè)容器空間:用于存放路徑
  • 有隊(duì)首隊(duì)尾標(biāo)志
  • O(1)復(fù)雜度的檢查隊(duì)列是否為空的接口或標(biāo)志
  • O(1)復(fù)雜度的返回容器容量的接口或標(biāo)志,容器容量應(yīng)該固定不變

使用一些面向?qū)ο蟮暮谀Х?,保存一些操作函?shù)防止代碼混亂。

  • 初始化函數(shù)
  • 釋放函數(shù)
  • 彈出操作函數(shù)
  • 壓入操作函數(shù)
  • 隊(duì)列實(shí)體

考慮到要存儲的是字符串,并且由于Windows API的參數(shù)需求,對于一個(gè)文件,我們需要存儲的路徑有兩個(gè)<源路徑,目的路徑>,對此應(yīng)該再使用一個(gè)路徑模型結(jié)構(gòu)體包裹他們,則空間的類型就相應(yīng)改變一下
新建 Queue.h Queue.c

Queue.h

  typedef struct _vector_queue queue;
  typedef struct _combine combine;

      |  返回值  | | 函數(shù)類型名 ||  參數(shù)類型  |
  typedef int       (*fpPushBack)(queue * __restrict, const char * __restrict, const char * __restrict);
  typedef const combine * (*fpPopFront)(queue *);
  typedef void      (*fpDelete)(queue *);

五個(gè)typedef不知道有沒有眼前一懵。,希望能夠很好的理解

前兩個(gè)是結(jié)構(gòu)體的聲明,分別對應(yīng)著 隊(duì)列模型 和 路徑模型。

后兩個(gè)是函數(shù)指針,作用是放在結(jié)構(gòu)體里,使C語言的結(jié)構(gòu)體也能夠擁有一些簡單的面向?qū)ο蠊δ?,例如成員函數(shù)功能,原理就是可以給這些函數(shù)指針類型的變量賦值。稍后例子更加明顯。試著解讀一下,很簡單的。

  struct _combine{
  char * src_from_path; /* 源路徑 */
  char * dst_to_path;  /* 目的路徑 */
  };

  struct _vector_queue{
    combine **   path_contain; /* 存儲路徑的容器主體 */
    unsigned int  rear;     /* 隊(duì)尾坐標(biāo) */
    unsigned int  front;    /* 隊(duì)首坐標(biāo) */
    int       empty;    /* 是否為空 */
    unsigned int  capcity;   /* 容器的容量 */
    fpPushBack   PushBack; /* 將元素壓入隊(duì)尾 */
    fpPopFront   PopFront; /* 將隊(duì)首出隊(duì) */
    fpDelete    Delete;  /* 析構(gòu)釋放整個(gè)隊(duì)列空間 */
  };

  /**
   * @version 1.0 2015/10/03
   * @author  wushengxin
   * @param  object 外部傳入的對象指針,相當(dāng)于 this
   * @function 初始化隊(duì)列模型,建立隊(duì)列實(shí)體,分配空間,以及設(shè)置屬性。
   */
  int newQueue(queue* object);

可以看到,上方的函數(shù)指針類型,被用在了結(jié)構(gòu)體內(nèi),此處少了一個(gè)初始化函數(shù),是因?yàn)椴淮蛩惆阉?dāng)作成員函數(shù)(借用面向?qū)ο笮g(shù)語)

在使用的時(shí)候可以直接obj_name.PushBack(..., ..., ...);

更詳細(xì)的可以看后面的實(shí)現(xiàn)部分。成為成員函數(shù)的三個(gè)函數(shù),將被實(shí)現(xiàn)為 static 函數(shù),不被外界訪問。

queue.c

 int newQueue(queue * object)
 {
   queue*   loc_que = object;
   combine**  loc_arr = NULL;

   loc_arr = (combine**)Malloc_s(CAPCITY * sizeof(combine*));
   if (!loc_arr)
     return 1;

   loc_que->capcity = CAPCITY; /* 容量 */
   loc_que->front = 0;    /* 隊(duì)首 */
   loc_que->rear = 0;    /* 隊(duì)尾 */

   loc_que->path_contain = loc_arr; /* 將分配好的空間,放進(jìn)對象中 */
   loc_que->PushBack = push_back;
   loc_que->PopFront = pop_front;
   loc_que->Delete  = del_queue;

   return 0;
 }

在初始化函數(shù)中,可以看到,設(shè)置了隊(duì)首隊(duì)尾以及容量,分配了容器空間,配置了成員函數(shù)。

最后三句配置函數(shù)的語句中,push_back, pop_front, del_queue在后方以static 函數(shù)實(shí)現(xiàn)。

但是由于沒有聲明,所以切記要將三個(gè)static函數(shù)的實(shí)現(xiàn)放在newQueue的前方

 /**
  * @version 1.0 2015/10/03
  * @author  wushengxin 
  * @param  object 外部傳入的對象指針 相當(dāng)于 this
  * @function 釋放整個(gè)隊(duì)列實(shí)體的空間
  */
 static void del_queue(queue * object)
 {
   Free_s(object->path_contain);
   return;
 }

 /**
  * @version 1.0 2015/10/03
  * @author  wushengxin
  * @param  object 外部傳入的對象指針 相當(dāng)于 this
        src  源路徑
        dst  目的路徑
  * @function 將外部傳入的<源路徑,目的路徑> 存入隊(duì)列中
  */
 static int push_back(queue * __restrict object, const char * __restrict src, const char * __restrict dst)
 {
   int times = 0;
   char*  loc_src = NULL; /* 本地變量,盡量利用寄存器以及緩存 */
   char*  loc_dst = NULL;
   combine* loc_com = NULL;
   queue*  loc_que = object;

   size_t  len_src = strlen(src); /* 獲取路徑長度 */
   size_t  len_dst = strlen(dst);
   size_t  rear = loc_que->rear;  /*獲取隊(duì)尾*/
   size_t  front = loc_que->front; /*獲取隊(duì)首*/

   loc_src = Malloc_s(len_src + 1); /* 分配空間 */
   if (!loc_src)
     return 1;

   loc_dst = Malloc_s(len_dst + 1);
   if (!loc_dst)
     return 2;
   strcpy(loc_src, src);
   strcpy(loc_dst, dst);

   loc_com = Malloc_s(sizeof(combine));
   if (!loc_com)
     return 3;
   loc_com->dst_to_path = loc_dst; 
   loc_com->src_from_path = loc_src;

   loc_que->path_contain[rear++] = loc_com; /* 將本地路徑加入實(shí)體 */
   loc_que->rear = (rear % CAPCITY);   /* 用數(shù)組實(shí)現(xiàn)循環(huán)隊(duì)列的步驟 */

   if (loc_que->rear == loc_que->front) 
     loc_que->empty = 0;
   return 0;
 }

 /**
  * @version 1.0 2015/10/03
  * @author  wushengxin
  * @param  object 外部傳入的對象指針
  */
 static const combine * pop_front(queue* object)
 {
   size_t  loc_front = object->front;          /*獲取當(dāng)前隊(duì)首*/
   combine* loc_com  = object->path_contain[loc_front]; /*獲取當(dāng)前文件名*/
   object->path_contain[loc_front] = NULL;   /*出隊(duì)操作*/
   object->front = ((object->front) + 1) % 20; /*完成出隊(duì)*/

   if (object->front == object->rear)
     object->empty = 1;
   else
     object->empty = 0;
   return loc_com;
 }

一個(gè)一個(gè)的說這些函數(shù)

del_queue:釋放函數(shù),直接調(diào)用Free_s

push_back:壓入函數(shù),將外部傳入的兩個(gè)原始的沒有組成的路徑字符串,組合成一個(gè)combine,并壓入路徑,每次都判斷并置是否為空標(biāo)志位,實(shí)際上這個(gè)函數(shù)中有累贅代碼的嫌疑,應(yīng)該再分出一個(gè)函數(shù),專門用來分配三個(gè)空間,防止這個(gè)函數(shù)過長(接近40行)

pop_front:彈出函數(shù),將隊(duì)列的隊(duì)首combine彈出,用于復(fù)制,但是這里有一個(gè)隱患,就是要將釋放的工作交給外者,如果疏忽大意的話,隱患就是內(nèi)存泄漏。

沒有特地的提供一個(gè)接口,用來判斷是否為空,因?yàn)楫?dāng)編譯器一優(yōu)化,也會將這種接口給優(yōu)化成直接使用成員的形式,某種形式上的內(nèi)聯(lián)。

隊(duì)列模型設(shè)計(jì)完畢,可以開始設(shè)計(jì)備份模型
備份模型可以回想一下之前的遍歷函數(shù),大體的結(jié)構(gòu)一樣,只是此處為了擴(kuò)展成多線程,需要添加一些多線程的調(diào)用函數(shù),以及為了規(guī)格化,需要添加一個(gè)二級界面
先設(shè)計(jì)一下二級界面

二級界面

思考一下,這個(gè)界面要做什么
選擇是否開始備份
并且源路徑需要在此處輸入
返回上一級
新建 backup.h backup.c 文件
在主界面選擇 1 以后就會調(diào)用二級界面的函數(shù)
列出二級界面的選項(xiàng)
1 Start Back up
2 Back To last level
backup.h

  /**
   * @version 1.0 2015/10/03
   * @author  wushengxin
   * function 顯示二級界面
   */
  void sec_main_windows();
backup.c

  void sec_main_windows()
  {
    char tmpBuf[256];
    int selects;
    do{
      setjmp(select_jmp);
      system("cls");
      puts("-------------------1. Back Up------------------ ");
      puts(" For This Select, You can choose Two Options: ");
      puts(" 1. Start Back up (The Directory Path That You Enter LATER) ");
      puts(" 2. Back To last level ");
      puts("----------------------------------------------- ");
      fprintf(stdout, "Enter Your Selection: ");
      fgets(tmpBuf, 256, stdin);
      sscanf(tmpBuf, "%d", &selects);
      if (selects != 1 && selects != 2 )
      {
        fprintf(stdout, "\n Your Select \" %s \" is Invalid!\n Try Again \n", tmpBuf);
        longjmp(select_jmp, 1);
      }

      switch (selects)
      {
        jmp_buf enter_path_jmp; 
      case 1:
      {
        char tmpBuf[LARGEST_PATH], tmpPath[LARGEST_PATH]; /* 使用棧分配空間,因?yàn)橹挥梅峙湟淮?*/
        setjmp(enter_path_jmp);     /* enter jump to there */
        puts(" Enter the Full Path You want to BackUp(e.g: C:/Programing/)");
        fprintf(stdout, " Or Enter q to back to select\nYour Enter : ");
        fgets(tmpBuf, LARGEST_PATH, stdin);
        sscanf(tmpBuf, "%s", tmpPath);
        if (_access(tmpPath, 0) != 0)  /*檢查路徑是否存在,有效*/
        {
          if (tmpPath[0] == 'q' || tmpPath[0] == 'Q') 
            longjmp(select_jmp, 0); /* 回到可以選擇返回的界面 */
          fprintf(stderr, "The Path You Enter is Not Exit! \n Try Again : ");
          longjmp(enter_path_jmp, 0); /* enter jump from here */
        }
      }
        break;
      case 2:
        return;
      default:
        break;
      }/* switch */
    } while (1);
    return;
  }

這個(gè)函數(shù)只說幾點(diǎn),首先是`switch`的`case 1`,之所以用**花括號**包裹起來的原因是,這樣才能在里面定義**本地變量**,直接在冒號后面定義是**編譯錯(cuò)誤**,這個(gè)特性可能比較少用,這里提一下,前面也有說過。
寫在最后方

剩下的就是編寫主要的功能函數(shù)和線程調(diào)用函數(shù)了。

相關(guān)文章

  • OpenCV實(shí)現(xiàn)智能視頻監(jiān)控

    OpenCV實(shí)現(xiàn)智能視頻監(jiān)控

    這篇文章主要為大家詳細(xì)介紹了OpenCV實(shí)現(xiàn)智能視頻監(jiān)控,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • udp socket客戶端和udp服務(wù)端程序示例分享

    udp socket客戶端和udp服務(wù)端程序示例分享

    這篇文章主要介紹了udp socket客戶端和udp服務(wù)端程序示例,需要的朋友可以參考下
    2014-03-03
  • c++結(jié)合opencv如何實(shí)現(xiàn)讀取多張圖片并顯示

    c++結(jié)合opencv如何實(shí)現(xiàn)讀取多張圖片并顯示

    這篇文章主要介紹了c++結(jié)合opencv如何實(shí)現(xiàn)讀取多張圖片并顯示問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Easyx實(shí)現(xiàn)掃雷游戲

    Easyx實(shí)現(xiàn)掃雷游戲

    這篇文章主要為大家詳細(xì)介紹了Easyx實(shí)現(xiàn)掃雷游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • 基于MFC實(shí)現(xiàn)貪吃蛇小游戲

    基于MFC實(shí)現(xiàn)貪吃蛇小游戲

    這篇文章主要為大家詳細(xì)介紹了基于MFC實(shí)現(xiàn)貪吃蛇小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • C語言printf詳細(xì)解析

    C語言printf詳細(xì)解析

    C中格式字符串printf()的一般形式為: %[標(biāo)志][輸出最小寬度][.精度][長度]類型, 其中方括號[]中的項(xiàng)為可選項(xiàng)。各項(xiàng)的意義介紹如下
    2013-09-09
  • 詳解C++中的vector容器及用迭代器訪問vector的方法

    詳解C++中的vector容器及用迭代器訪問vector的方法

    使用迭代器iterator可以更方便地解引用和訪問成員,當(dāng)然也包括vector中的元素,本文就來詳解C++中的vector容器及用迭代器訪問vector的方法,需要的朋友可以參考下
    2016-05-05
  • C語言宏函數(shù)container of()簡介

    C語言宏函數(shù)container of()簡介

    這篇文章介紹了C語言宏函數(shù)container of(),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-12-12
  • C語言鏈表詳解及代碼分析

    C語言鏈表詳解及代碼分析

    這篇文章主要介紹了C語言鏈表詳解及代碼分析,說明了鏈表的定義與概念,通過詳細(xì)的代碼展示了基于鏈表的增刪改查功能,希望本文能對你有所幫助
    2021-06-06
  • C++大數(shù)模板(推薦)

    C++大數(shù)模板(推薦)

    本篇文章是對C++大數(shù)模板的程序代碼進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05

最新評論