CouchDB 将二进制文件拆分为块或部分上传/下载

xcitsw88  于 2022-12-09  发布在  CouchDB
关注(0)|答案(1)|浏览(205)

由于某种原因,我使用couchdb作为内容管理来上传二进制数据文件,没有像mongoDB那样的GridFs支持来上传大文件,所以我需要上传块文件,然后作为一个文件检索它们。
这是我代码

public string InsertDataToCouchDb(string dbName, string id, string filename, byte[] image)
  {
    var connection = System.Configuration.ConfigurationManager.ConnectionStrings["CouchDb"].ConnectionString;
    using (var db = new MyCouchClient(connection, dbName))
    {

      // HERE I NEED TO UPLOAD MY IMAGE BYTE[] AS CHUNKS 
      var artist = new couchdb
      {
        _id = id,
        filename = filename,
        Image = image
      };

      var response = db.Entities.PutAsync(artist);
      return response.Result.Content._id;
    }
  }

  public byte[] FetchDataFromCouchDb(string dbName, string id)
  {
    var connection = System.Configuration.ConfigurationManager.ConnectionStrings["CouchDb"].ConnectionString;
    using (var db = new MyCouchClient(connection, dbName))
    {
      //HERE I NEED TO RETRIVE MY FULL IMAGE[] FROM CHUNKS
      var test = db.Documents.GetAsync(id, null);
      var doc = db.Serializer.Deserialize<couchdb>(test.Result.Content);
      return doc.Image;
    }
  }

谢谢你

6pp0gazn

6pp0gazn1#

将图像数据放在CouchDB文档中是一个***糟糕的主意***。千万不要这样做。这就是CouchDB附件的用途。通过文档更新使数据库中的冗余blob数据膨胀的潜在可能性肯定会对玩具数据库以外的任何东西产生重大的负面影响。
此外,似乎还缺乏对async/await如何工作的理解,因为OP中的代码正在调用async方法,例如db.Entities.PutAsync(artist),而没有await-每次调用肯定都会失败(如果编译器甚至允许代码)。我强烈推荐阅读微软文档Asynchronous programming with async and await
至于“组块”:如果图像数据太大,需要以其他方式进行流传输,那么通过字节数组传递数据的做法看起来很糟糕。如果图像相对较小,则直接使用Attachment.PutAsync即可。
虽然MyCouch v7.6的Attachment.PutAsync不支持流(有效的分块),但存在Support Streams for attachments #177 PR,它支持流,而且看起来很不错。
这是一个单页的C# .Net Core控制台应用程序,它使用PR 177提供的非常高效的流,将给定文件作为附件上传到特定文档。虽然代码使用PR 177,但最重要的是,它对blob数据使用Attachments。用字节数组替换流相当简单。

我的治疗床+ PR 177

在控制台中获取MyCouch源,然后应用PR 177

$ git clone https://github.com/danielwertheim/mycouch.git
$ cd mycouch
$ git pull origin 15a1079502a1728acfbfea89a7e255d0c8725e07

(我不知道git,所以可能有一个更好的方法来获得公关)

我的治疗床上传程序

采用VS 2019
1.创建名为“MyCouchUploader”的新.Net Core控制台应用程序项目和解决方案
1.将使用PR 177拉动的MyCouch项目添加到解决方案中
1.添加MyCouch项目作为MyCouchUploader依赖项
1.添加Nuget包“Microsoft.AspNetCore.StaticFiles”作为MyCouchUploader依赖项
1.将Program.cs的内容替换为以下代码:

using Microsoft.AspNetCore.StaticFiles;
using MyCouch;
using MyCouch.Requests;
using MyCouch.Responses;
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Threading.Tasks;

namespace MyCouchUploader
{
    class Program
    {
        static async Task Main(string[] args)
        {
            // args: scheme, database, file path of asset to upload.
            if (args.Length < 3)
            {
                Console.WriteLine("\nUsage: MyCouchUploader scheme dbname filepath\n");
                return;
            }

            var opts = new
            {
                scheme = args[0],
                dbName = args[1],
                filePath = args[2]
            };
            
            Action<Response> check = (response) =>
            {
                if (!response.IsSuccess) throw new Exception(response.Reason);
            };

            try
            {
                // canned doc id for this app
                const string docId = "SO-68998781";
                const string attachmentName = "Image";

                DbConnectionInfo cnxn = new DbConnectionInfo(opts.scheme, opts.dbName)
                { // timely fail if scheme is bad
                    Timeout = TimeSpan.FromMilliseconds(3000)
                };
                MyCouchClient client = new MyCouchClient(cnxn);
                // ensure db is there
                GetDatabaseResponse info = await client.Database.GetAsync();
                check(info);
                // delete doc for succcessive program runs 
                DocumentResponse doc = await client.Documents.GetAsync(docId);
                if (doc.StatusCode == HttpStatusCode.OK)
                {
                    DocumentHeaderResponse del = await client.Documents.DeleteAsync(docId, doc.Rev);
                    check(del);
                }
                // sniff file for content type
                FileExtensionContentTypeProvider provider = new FileExtensionContentTypeProvider();
                if (!provider.TryGetContentType(opts.filePath, out string contentType))
                {
                    contentType = "application/octet-stream";
                }
                
                // create a hash for silly verification
                using var md5 = MD5.Create();                
                using Stream stream = File.OpenRead(opts.filePath);
                byte[] fileHash = md5.ComputeHash(stream);

                stream.Position = 0;
                // Use PR 177, sea-locks:stream-attachments.
                DocumentHeaderResponse put = await client.Attachments.PutAsync(new PutAttachmentStreamRequest(
                    docId,
                    attachmentName,
                    contentType,
                    stream // :-D
                ));
                check(put);                                

                // verify 
                AttachmentResponse verify = await client.Attachments.GetAsync(docId, attachmentName);
                check(verify);                 
                if (fileHash.SequenceEqual(md5.ComputeHash(verify.Content)))
                {
                    Console.WriteLine("Atttachment verified.");
                }
                else
                {
                    throw new Exception(String.Format("Attachment failed verification with status code {0}", verify.StatusCode));
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Fail! {0}", e.Message);
            }
        }
    }
}

若要执行:

$ MyCouchdbUploader http://name:password@localhost:5984 dbname path-to-local-image-file

使用Fauxton目视验证文件附件。

相关问题