使用Mongoose讓你簡單快樂地上傳檔案

2016-04-22    分類:C/C++開發、程式設計開發、首頁精華0人評論發表於2016-04-22

本文由碼農網 – 小峰原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃

想簡單而快樂地上傳任何大小的檔案?那麼你肯定需要Mongoose。

下面是你的步驟

首先,我們需要一個有“上傳按鈕”的網頁,它可能是這樣的:

<html><body>Upload example
<form method="POST" action="upload ectype="multipart/form-data">
<input type="file" name="file" /> 
<br/> <input type="submit" value="Upload"/>

現在,我們需要實現一個事件處理程式。通常是Mongoose事件處理程式。這是它的開頭:

static void handle_upload(struct mg_connection *nc, int ev, void *p) {
struct file_writer_data *data = (struct file_writer_data *) nc->user_data;
struct mg_http_multipart_part *mp = (struct mg_http_multipart_part*)p;

看一看mg_http_multipart_part結構。它包含有關上傳過程的有用資訊。

在處理程式中,我們需要關注下列事件:

MG_EV_HTTP_PART_BEGIN:新傳入的資料請求,我們可以在這裡做一些準備。例如,我們可以開啟該檔案。

case MG_EV_HTTP_PART_BEGIN:
  .....
  data = calloc(1, sizeof(struct file_writer_data));
  /* We use temp file, but it is possible to use real file name;
     mp->file_name contains it */
  data->fp = tmpfile();  
        data->bytes_written = 0;
  ....

MG_EV_HTTP_PART_DATA:資料迴圈讀取,mp包含指標資料和它的長度。在這裡寫到檔案中。

case MG_EV_HTTP_PART_DATA: 
    ...
    fwrite(mp->data.p, 1, mp->data.len, data->fp
    ....

MG_EV_HTTP_PART_END:資料完成後,及時關閉檔案。

case MG_EV_HTTP_PART_END:  
  ....
  fclose(data->fp);
  ....

整理到一起:

static void handle_upload(struct mg_connection *nc, int ev, void *p) {
  struct file_writer_data *data = 
     (struct file_writer_data *) nc->user_data;
  struct mg_http_multipart_part *mp = 
     (struct mg_http_multipart_part*)p;
  switch (ev) {
    case MG_EV_HTTP_PART_BEGIN: {
      if (data == NULL) {
        data = calloc(1, sizeof(struct file_writer_data));
        data->fp = tmpfile();
        data->bytes_written = 0;
        if (data->fp == NULL) {
          mg_printf(nc, "%s",
                    "HTTP/1.1 500 Failed to open a file\r\n"
                    "Content-Length: 0\r\n\r\n");
          nc->flags |= MG_F_SEND_AND_CLOSE;
          return;
        }
        nc->user_data = (void *) data;
      }
      break;
    }
    case MG_EV_HTTP_PART_DATA: {
      if (fwrite(mp->data.p, 1, 
           mp->data.len, data->fp) != mp->data.len) {
        mg_printf(nc, "%s",
                  "HTTP/1.1 500 Failed to write to a file\r\n"
                  "Content-Length: 0\r\n\r\n");
        nc->flags |= MG_F_SEND_AND_CLOSE;
        return;
      }
      data->bytes_written += mp->data.len;
      break;
    }
    case MG_EV_HTTP_PART_END: {
      mg_printf(nc,
                "HTTP/1.1 200 OK\r\n"
                "Content-Type: text/plain\r\n"
                "Connection: close\r\n\r\n"
                "Written %ld of POST data to a temp file\n\n",
                (long) ftell(data->fp));
      nc->flags |= MG_F_SEND_AND_CLOSE;
      fclose(data->fp);
      free(data);
      nc->user_data = NULL;
      break;
    }
  }
}

不要忘了建立監聽連線:

nc = mg_bind(&mgr, "1234", ev_handler);

以及,註冊HTTP埠(此為可選專案):

mg_register_http_endpoint(nc, "/upload", handle_upload);

以上是基礎。Mongoose 將處理其餘部分。

你必須知道的兩件事

你可以使用同樣的方法上傳檔案到嵌入式裝置。Mongoose會快速解析multipart請求和問題事件,正如我們前面所描述的那樣,而不必等待整個請求被緩衝。所以,你可以上傳千兆位元組的檔案,即使你的裝置的記憶體只有幾KB。

並且,Mongoose能做的不僅如此。如果你需要的只是儲存上傳的檔案到檔案系統(而不是程式設計快閃記憶體晶片等),那麼你可以使用mg_file_upload_handler輔助函式。在這種情況下,事件處理程式變成了:

void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
  switch (ev) {
    ...
    case MG_EV_HTTP_PART_BEGIN:
    case MG_EV_HTTP_PART_DATA:
    case MG_EV_HTTP_PART_END:
      mg_file_upload_handler(nc, ev, ev_data, upload_fname);
      break;
   }
 }

非常簡單。

你可以在這裡下載完整的原始碼。

譯文連結:http://www.codeceo.com/article/mongoose-upload-file.html
英文原文:A Simple Way to Upload Files Using Mongoose
翻譯作者:碼農網 – 小峰
轉載必須在正文中標註並保留原文連結、譯文連結和譯者等資訊。]

相關文章