mongodb GridFS 大結構文件系統

GridFS是一種在MongoDB中存儲大二進制文件的機制。使用GridFS存文件有如下幾個原因:

1、利用Grid可以簡化需求。要是已經用了MongoDB,GridFS就可以不需要使用獨立文件存儲架構。
2、GridFS會直接利用業已建立的複製或分片機制,所以對於文件存儲來說故障恢復和擴展都很容易。
3、GridFS可以避免用於存儲用戶上傳內容的文件系統出現的某些問題。例如,
GridFS在同一個目錄下放置大量的文件是沒有任何問題的。
4、GridFS不產生磁盤碎片,因爲MongoDB分配數據文件空間時以2GB爲一塊。

使用場景:

1) 有大量的上傳圖片(用戶上傳或者系統本身的文件發佈等)
2) 文件的量級處於飛速增長,有可能打到單機操作系統自己的文件系統的查詢性能瓶頸,甚至超過單機硬盤的擴容範圍.
3) 文件的備份(不適用gridfs這種三方也可以做,但是不盡方便),文件系統訪問的故障轉移和修復..
4) 文件的索引,存儲除文件本身以外還需要關聯更多的元數據信息(比如,不僅僅存儲文件,還要保存一些文件的發佈式作者/發佈時間/文件tag屬性等等自定義信息)並且需要索引的。
5) 基於4),對文件的分類模糊,如果採用操作系統的文件系統,文件夾分類關係混亂或者無法分類時
6) 當前系統是基於web的,對圖片的訪問根據url了規則路由的..(如搭配nginx用,讓nginx直接讀取gridfs的文件)
7) 文件尺寸較小,而且衆多,且文件有可能被遷移/刪除等
8)用於存儲和恢復那些超過16M(BSON文件限制)的文件

接口代碼如下:
mongoc_gridfs_t提供的是MongoDB 的gridfs 文件系統的接口。地理信息文件系統包含gridfs_filesgridfs_file_lists以及相關的api。
mongoc_gridfs_t 是非線程安全的。釋放mongoc_gridfs_t之前需要先釋放mongoc_gridfs_file_tmongoc_gridfs_file_list_t

示例代碼如下

#include <mongoc.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main (int argc, char *argv[])
{
   mongoc_gridfs_t *gridfs;
   mongoc_gridfs_file_t *file;
   mongoc_gridfs_file_list_t *list;
   mongoc_gridfs_file_opt_t opt = { 0 };
   mongoc_client_t *client;
   mongoc_stream_t *stream;
   bson_t query;
   bson_t child;
   bson_error_t error;
   ssize_t r;
   char buf[4096];
   mongoc_iovec_t iov;
   const char * filename;
   const char * command;
   if (argc < 2) {
      fprintf(stderr, "usage - %s command ...\n", argv[0]);
      return 1;
   }
   mongoc_init();
   iov.iov_base = (void *)buf;
   iov.iov_len = sizeof buf;
   /* connect to localhost client */
   client = mongoc_client_new ("mongodb://127.0.0.1:27017");//創建連接
   assert(client);//檢查創建連接結果
   /* grab a gridfs handle in test prefixed by fs */
   gridfs = mongoc_client_get_gridfs (client, "test", "fs", &error);
   assert(gridfs);
   command = argv[1];
   filename = argv[2];
   if (strcmp(command, "read") == 0) {//讀取指定文檔
      if (argc != 3) {
         fprintf(stderr, "usage - %s read filename\n", argv[0]);
         return 1;
      }
      file = mongoc_gridfs_find_one_by_filename(gridfs, filename, &error);
      assert(file);
      stream = mongoc_stream_gridfs_new (file);
      assert(stream);
      for (;;) {
         r = mongoc_stream_readv (stream, &iov, 1, -1, 0);
         assert (r >= 0);
         if (r == 0) {
            break;
         }
         if (fwrite (iov.iov_base, 1, r, stdout) != r) {
            MONGOC_ERROR ("Failed to write to stdout. Exiting.\n");
            exit (1);
         }
      }
      mongoc_stream_destroy (stream);
      mongoc_gridfs_file_destroy (file);
   } else if (strcmp(command, "list") == 0) {//列舉所有文檔
      bson_init (&query);
      bson_append_document_begin (&query, "$orderby", -1, &child);
      bson_append_int32 (&child, "filename", -1, 1);
      bson_append_document_end (&query, &child);
      bson_append_document_begin (&query, "$query", -1, &child);
      bson_append_document_end (&query, &child);
      list = mongoc_gridfs_find (gridfs, &query);
      bson_destroy (&query);
      while ((file = mongoc_gridfs_file_list_next (list))) {
         const char * name = mongoc_gridfs_file_get_filename(file);
         printf("%s\n", name ? name : "?");
         mongoc_gridfs_file_destroy (file);
      }
      mongoc_gridfs_file_list_destroy (list);
   } else if (strcmp(command, "write") == 0) {//寫文檔
      if (argc != 4) {
         fprintf(stderr, "usage - %s write filename input_file\n", argv[0]);
         return 1;
      }
      stream = mongoc_stream_file_new_for_path (argv [3], O_RDONLY, 0);
      assert (stream);
      opt.filename = filename;
      file = mongoc_gridfs_create_file_from_stream (gridfs, stream, &opt);
      assert(file);
      mongoc_gridfs_file_save(file);
      mongoc_gridfs_file_destroy(file);
   } else {
      fprintf(stderr, "Unknown command");
      return 1;
   }
   mongoc_gridfs_destroy (gridfs);
   mongoc_client_destroy (client);
   mongoc_cleanup ();
   return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章