程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> Windows體系下應用C說話編寫單線程的文件備份法式

Windows體系下應用C說話編寫單線程的文件備份法式

編輯:關於C++

Windows體系下應用C說話編寫單線程的文件備份法式。本站提示廣大學習愛好者:(Windows體系下應用C說話編寫單線程的文件備份法式)文章只能為提供參考,不一定能成為您想要的結果。以下是Windows體系下應用C說話編寫單線程的文件備份法式正文


寫在最後方

源途徑:即 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("-------------------------------------------------");

對界面略微有了一些修改。

新增了第三行和第四行的 體系默許目標途徑和以後應用的目標途徑。

新增了倒數第四行的檢查目標途徑汗青記載的功效。

在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);

外面用到了一些新的特征,假如應用 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;
   }

  第一個函數是用內部界說的宏 `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);

  對應的完成中,會界說一個靜態的字符數組,且在頭文件中可以或許看見,許多是在`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;
   }

有了下面的代碼,主界面就再次可以或許無誤運轉了,那末剩下的就是完成,設置目標途徑,存儲目標途徑到當地,顯示目標途徑,分離對應主界面的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)
    {
      time_t ctimes; 
      time(&ctimes); /* 獲得時光 */
      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` 函數的應用網路上的引見加倍周全,這裡不做說明。

    完成了存儲的函數以後,就是完成從鍵盤讀取而且設置默許途徑
設置目標途徑 set_enter_path

在此處須要停上去在此思慮一下,假如用戶輸出了毛病的途徑(有效途徑或許歹意途徑),也應當被讀取嗎?所以應當增長一個檢討,用於確認途徑的有用性。
setPath.h

    #include <string.h>
    #include <io.h> /* _access */
    enum {NOT_EXIST = 0, EXIST = 1};
    /**
     * @version 1.0 2015/10/02
     * @author  wushengxin
     * @function 用於讀取從鍵盤輸出的途徑並將之設置為默許途徑,並存儲。
     */
    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]; /** 暫時緩沖區 **/
      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); /* 獲得斷定數的輸出 */
        if (intJudge != 0)
        {
          if (to_path_buf[strlen(to_path_buf) - 1] != '/')
            strcat(to_path_buf, "/");/* 假如最初一個字符不是'/',則添加,這裡沒斟酌能否越界 */
          store_hist_path(to_path_buf);
          break;
        } /* if(intJudge) */
      }/* while (1) */
      return;
    }/* set_enter_path */

    這一組函數的功效略微龐雜,年夜體來講就是 `讀取途徑輸出->檢討途徑有用性->讀取斷定數->能否停止輪回`

    個中`_access` 函數有些淵源,由於這個函數被年夜家所熟知的是這個情勢 `access`,但因為這個情勢是 **POSIX** 尺度,故 **Windows** 將其完成為`_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;
    }

剩下最初一個掃尾任務

初始化途徑
每次法式啟動的時刻,我們都邑讀取當地文件,獲得上一次法式應用的最初一個途徑,作為以後應用的目標途徑
初始化目標途徑 init_path

setPath.h

    /**
     * @versions 1.0 2015/10/02
     * @author  wushengxin
     * @function 用於每次法式啟動時初始化目標途徑
     */
    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'; /* 清除一個過剩的 ‘\n' */
        strcpy(to_path_buf, last_path);
      }
      return;
    }

    如許就年夜功樂成了,關於這個函數中的後`8`行代碼,沒應用習用的`fgets 合營 sscanf` 是由於假如這麼干的話,須要搭配一個`memset`函數清零,前面會有說明。

關於memset的說明
這個函數關於年夜的內存塊的初始化現實上是很慢的,固然我們這個30KB閣下年夜概的內存能夠影響還沒有那末年夜,然則上兆今後,挪用memset就是一種機能成績了,許多情形下,編譯器在開啟高優化品級以後會主動幫你撤消memset的隱式挪用
甚麼隱式挪用,例如 init_path的第二行代碼,聲明而且用花括號初始化這個數組的時刻,就會挪用隱式memset。

寫在中央

下面完成了界面的年夜部門功效,剩下的就是備份這個重要功效。
在完成備份之前,起首想一想要若何結構這個備份模子

既然是備份,假如不想擴大為多線程的情勢,參考第一次寫的遍歷函數(show_structure)直接找到文件便挪用Windows API(稍後引見)停止復制便可,不須要講待備份的文件途徑保留上去。
假如要斟酌多線程擴大,我們就須要從長計議。
關於一個備份模子,最好的莫過於應用一個隊列,照舊實施的是遍歷形式,然則將找到的文件途徑保留,並放入一個先輩先出的隊列中,如許我們就可以夠包管在擴大成多線程的時刻,可以有一個很清楚的模子參考。
那末如今的義務就是完成這個用於備份的隊列模子。
隊列模子

  • 應當有一個容器空間:用於寄存途徑
  • 有隊首隊尾標記
  • O(1)龐雜度的檢討隊列能否為空的接口或標記
  • O(1)龐雜度的前往容器容量的接口或標記,容器容量應當固定不變

應用一些面向對象的黑魔法,保留一些操作函數避免代碼凌亂。

  • 初始化函數
  • 釋放函數
  • 彈出操作函數
  • 壓入操作函數
  • 隊列實體

斟酌到要存儲的是字符串,而且因為Windows API的參數需求,關於一個文件,我們須要存儲的途徑有兩個<源途徑,目標途徑>,對此應當再應用一個途徑模子構造體包裹他們,則空間的類型就響應轉變一下
新建 Queue.h Queue.c

Queue.h

  typedef struct _vector_queue queue;
  typedef struct _combine combine;

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

五個typedef不曉得有無面前一懵。,願望可以或許很好的懂得

前兩個是構造體的聲明,分離對應著 隊列模子 和 途徑模子。

後兩個是函數指針,感化是放在構造體裡,使C說話的構造體也可以或許具有一些簡略的面向對象功效,例如成員函數功效,道理就是可以給這些函數指針類型的變量賦值。稍後例子加倍顯著。試著解讀一下,很簡略的。

  struct _combine{
  char * src_from_path; /* 源途徑 */
  char * dst_to_path;  /* 目標途徑 */
  };

  struct _vector_queue{
    combine **   path_contain; /* 存儲途徑的容器主體 */
    unsigned int  rear;     /* 隊尾坐標 */
    unsigned int  front;    /* 隊首座標 */
    int       empty;    /* 能否為空 */
    unsigned int  capcity;   /* 容器的容量 */
    fpPushBack   PushBack; /* 將元素壓入隊尾 */
    fpPopFront   PopFront; /* 將隊首出隊 */
    fpDelete    Delete;  /* 析構釋放全部隊列空間 */
  };

  /**
   * @version 1.0 2015/10/03
   * @author  wushengxin
   * @param  object 內部傳入的對象指針,相當於 this
   * @function 初始化隊列模子,樹立隊列實體,分派空間,和設置屬性。
   */
  int newQueue(queue* object);

可以看到,上方的函數指針類型,被用在了卻構體內,此處少了一個初始化函數,是由於不盤算把他看成成員函數(借用面向對象術語)

在應用的時刻可以直接obj_name.PushBack(..., ..., ...);

更具體的可以看前面的完成部門。成為成員函數的三個函數,將被完成為 static 函數,不被外界拜訪。

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;    /* 隊首 */
   loc_que->rear = 0;    /* 隊尾 */

   loc_que->path_contain = loc_arr; /* 將分派好的空間,放進對象中 */
   loc_que->PushBack = push_back;
   loc_que->PopFront = pop_front;
   loc_que->Delete  = del_queue;

   return 0;
 }

在初始化函數中,可以看到,設置了隊首隊尾和容量,分派了容器空間,設置裝備擺設了成員函數。

最初三句設置裝備擺設函數的語句中,push_back, pop_front, del_queue在前方以static 函數完成。

然則因為沒有聲明,所以切紀要將三個static函數的完成放在newQueue的後方

 /**
  * @version 1.0 2015/10/03
  * @author  wushengxin 
  * @param  object 內部傳入的對象指針 相當於 this
  * @function 釋放全部隊列實體的空間
  */
 static void del_queue(queue * object)
 {
   Free_s(object->path_contain);
   return;
 }

 /**
  * @version 1.0 2015/10/03
  * @author  wushengxin
  * @param  object 內部傳入的對象指針 相當於 this
        src  源途徑
        dst  目標途徑
  * @function 將內部傳入的<源途徑,目標途徑> 存入隊列中
  */
 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;  /*獲得隊尾*/
   size_t  front = loc_que->front; /*獲得隊首*/

   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; /* 將當地途徑參加實體 */
   loc_que->rear = (rear % CAPCITY);   /* 用數組完成輪回隊列的步調 */

   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;          /*獲得以後隊首*/
   combine* loc_com  = object->path_contain[loc_front]; /*獲得以後文件名*/
   object->path_contain[loc_front] = NULL;   /*出隊操作*/
   object->front = ((object->front) + 1) % 20; /*完成出隊*/

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

一個一個的說這些函數

del_queue:釋放函數,直接挪用Free_s

push_back:壓入函數,將內部傳入的兩個原始的沒有構成的途徑字符串,組分解一個combine,並壓入途徑,每次都斷定並置能否為空標記位,現實上這個函數中有包袱代碼的嫌疑,應當再分出一個函數,專門用來分派三個空間,避免這個函數太長(接近40行)

pop_front:彈出函數,將隊列的隊首combine彈出,用於復制,然則這裡有一個隱患,就是要將釋放的任務交給外者,假如忽視年夜意的話,隱患就是內存洩露。

沒有專程的供給一個接口,用來斷定能否為空,由於當編譯器一優化,也會將這類接口給優化成直接應用成員的情勢,某種情勢上的內聯。

隊列模子設計終了,可以開端設計備份模子
備份模子可以回憶一下之前的遍歷函數,年夜體的構造一樣,只是此處為了擴大成多線程,須要添加一些多線程的挪用函數,和為了規格化,須要添加一個二級界面
先設計一下二級界面

二級界面

思慮一下,這個界面要做甚麼
選擇能否開端備份
而且源途徑須要在此處輸出
前往上一級
新建 backup.h backup.c 文件
在主界面選擇 1 今後就會挪用二級界面的函數
列出二級界面的選項
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]; /* 應用棧分派空間,由於只用分派一次 */
        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;
  }

這個函數只說幾點,起首是`switch`的`case 1`,之所以用**花括號**包裹起來的緣由是,如許能力在外面界說**當地變量**,直接在冒號前面界說是**編譯毛病**,這個特征能夠比擬罕用,這裡提一下,後面也有說過。
寫在最初方

剩下的就是編寫重要的功效函數和線程挪用函數了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved