项目需要将音视频文件上传服务器,考虑并发要求高,通过七牛来实现。

做了一个简易的压力测试,同时上传多个文件,七牛自己应该有队列处理并发请求,我无论同时提交多少个文件,七牛是批量一个个排队处理了。

一个1.5MB的文件,上传时间大概2-3秒,感觉不错。

直接上代码

using Qiniu.IO;
using Qiniu.IO.Resumable;
using Qiniu.RPC;
using Qiniu.RS;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks; namespace qiniuTest
{
/// <summary>
/// 文件上传有两种方式:
/// 一种是以普通方式直传文件,简称普通上传;
/// 另一种方式是断点续上传,断点续上传在网络条件很一般的情况下也能有出色的上传速度,而且对大文件的传输非常友好。
/// </summary>
class Program
{
static string bucket = "cvteXXXX"; static void Main(string[] args)
{
Qiniu.Conf.Config.ACCESS_KEY = "6QQ7Cnz4bljdkQOWQ5UOAheVCAd0bCa7Tc5XXXXX";
Qiniu.Conf.Config.SECRET_KEY = "9rUGnbFtvm-PLWcZeOR6ed9MUjZ4bKitf7YXXXX"; string fileKey = "应用系统全貌图.png";
//GetFileStat(bucket, fileKey); //小文件直传
string fileName = "CVTE信息系统-业务功能架构图-IM和企业微信.jpg";
//PutFile(bucket, Guid.NewGuid().ToString() + fileName, "d:\\" + fileName); //在asp.net mvc中的文件上传
//ResumablePutFile(bucket, Guid.NewGuid().ToString(), Path.Combine(path, Request.Form[0])); //大文件上传
//string bigFileName = "eclipse-java-luna-SR1-win32-x86_64.zip";
//ResumablePutFile(bucket, Guid.NewGuid().ToString() + bigFileName, "d:\\Software\\" + bigFileName); //GetFile("7xq1c1.com1.z0.glb.clouddn.com", fileKey); //********************** 压力测试 **********************
// 获取线程池的最大线程数和维护的最小空闲线程数 int maxThreadNum, portThreadNum; int minThreadNum; ThreadPool.GetMaxThreads(out maxThreadNum, out portThreadNum); ThreadPool.GetMinThreads(out minThreadNum, out portThreadNum); Console.WriteLine("最大线程数:{0}", maxThreadNum); Console.WriteLine("最小空闲线程数:{0}", minThreadNum);
int loopNumber = ; //内部循环次数
int ConcurrentNumber = ; //并发数 for (int i = ; i < ConcurrentNumber; i++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(TaskProc), loopNumber);
} Console.ReadLine();
} public static void TaskProc(object loopNumber)
{
int LoopNumber = Convert.ToInt32(loopNumber);
Console.WriteLine("启动任务,小文件直传");
//小文件直传 压力测试
for (int i = ; i < LoopNumber; i++)
{ string fileName = "WinRAR.exe";
Console.WriteLine(i + "开始" + fileName + System.DateTime.Now);
PutFile(bucket, Guid.NewGuid().ToString() + fileName, "D:\\" + fileName);
Console.WriteLine(i + "完成" + fileName + System.DateTime.Now); string fileName1 = "WinRAR1.exe";
Console.WriteLine(i + "开始" + fileName1 + System.DateTime.Now);
PutFile(bucket, Guid.NewGuid().ToString() + fileName1, "D:\\" + fileName1);
Console.WriteLine(i + "完成" + fileName1 + System.DateTime.Now); } } /// <summary>
/// 查看单个文件属性信息
/// </summary>
/// <param name="bucket">七牛云存储空间名</param>
/// <param name="key">文件key,也就是文件名</param>
public static void GetFileStat(string bucket, string key)
{
RSClient client = new RSClient();
Entry entry = client.Stat(new EntryPath(bucket, key));
if (entry.OK)
{
Console.WriteLine("Hash: " + entry.Hash);
Console.WriteLine("Fsize: " + entry.Fsize);
Console.WriteLine("PutTime: " + entry.PutTime);
Console.WriteLine("MimeType: " + entry.MimeType);
Console.WriteLine("Customer: " + entry.Customer);
}
else
{
Console.WriteLine("Failed to Stat");
}
} /// <summary>
/// 删除单个文件
/// </summary>
/// <param name="bucket">文件所在的空间名</param>
/// <param name="key">文件key</param>
public static void Delete(string bucket, string key)
{
Console.WriteLine("\n===> Delete {0}:{1}", bucket, key);
RSClient client = new RSClient();
CallRet ret = client.Delete(new EntryPath(bucket, key));
if (ret.OK)
{
Console.WriteLine("Delete OK");
}
else
{
Console.WriteLine("Failed to delete");
}
} /// <summary>
/// 批量删除文件
/// </summary>
/// <param name="bucket">文件所在的空间名</param>
/// <param name="keys">文件key</param>
public static void BatchDelete(string bucket, string[] keys)
{
RSClient client = new RSClient();
List<EntryPath> EntryPaths = new List<EntryPath>();
foreach (string key in keys)
{
Console.WriteLine("\n===> Stat {0}:{1}", bucket, key);
EntryPaths.Add(new EntryPath(bucket, key));
}
client.BatchDelete(EntryPaths.ToArray());
} /// <summary>
/// 普通方式直传文件
/// </summary>
/// <param name="bucket">文件所在的空间名</param>
/// <param name="key">您可以自行定义文件Key,一般GUID</param>
/// <param name="fname">文件路径+文件名</param>
public static void PutFile(string bucket, string key, string fname)
{
var policy = new PutPolicy(bucket, );
string upToken = policy.Token();
PutExtra extra = new PutExtra();
IOClient client = new IOClient();
client.PutFile(upToken, key, fname, extra);
} /// <summary>
/// 断点续上传方式,传大文件用这种方式
/// </summary>
/// <param name="bucket">文件所在的空间名</param>
/// <param name="key">您可以自行定义文件Key,一般GUID</param>
/// <param name="fname">文件路径+文件名</param>
public static void ResumablePutFile(string bucket, string key, string fname)
{
Console.WriteLine("\n===> ResumablePutFile {0}:{1} fname:{2}", bucket, key, fname);
PutPolicy policy = new PutPolicy(bucket, );
string upToken = policy.Token();
Settings setting = new Settings();
ResumablePutExtra extra = new ResumablePutExtra();
ResumablePut client = new ResumablePut(setting, extra);
client.PutFile(upToken, fname, Guid.NewGuid().ToString());
} /// <summary>
/// Get方式获取文件
/// </summary>
/// <param name="domain">文件域</param>
/// <param name="key">文件Key</param>
public static void GetFile(string domain, string key)
{
System.Diagnostics.Process.Start("http://" + domain + "/" + key);
}
}
}

另外,七牛的魔法变量非常强大,多用于增强回调

魔法变量

魔法变量是一组预先定义的变量,可以使用 $(var) 或 $(var.field_name) 形式求值。

目前可用的魔法变量如下:

变量名 包含子项 变量说明 适用范围
bucket   获得上传的目标空间名。  
key   获得文件保存在空间中的资源名。  
etag   文件上传成功后的HTTP ETag。若上传时未指定资源ID,Etag将作为资源ID使用。  
fname   上传的原始文件名。 不支持用于分片上传
fsize   资源尺寸,单位为字节。  
mimeType   资源类型,比如JPG图片的资源类型为image/jpg  
endUser   上传时指定的endUser字段,通常用于区分不同终端用户的请求。  
persistentId   音视频转码持久化的进度查询ID。  
exif 获取所上传图片的Exif信息。

该变量包含子字段,比如对$(exif.ApertureValue.val)取值将得到该图片拍摄时的光圈值。

暂不支持用于saveKey
imageInfo 获取所上传图片的基本信息。

该变量包含子字段,比如对$(imageInfo.width)取值将得到该图片的宽度。

暂不支持用于saveKey
year   上传时的年份。 暂不支持用于’returnBody’、’callbackBody’中
mon   上传时的月份。 暂不支持用于’returnBody’、’callbackBody’中
day   上传时的日期。 暂不支持用于’returnBody’、’callbackBody’中
hour   上传时的小时。 暂不支持用于’returnBody’、’callbackBody’中
min   上传时的分钟。 暂不支持用于’returnBody’、’callbackBody’中
sec   上传时的秒钟。 暂不支持用于’returnBody’、’callbackBody’中
avinfo 音视频资源的元信息。 暂不支持用于’saveKey’中
imageAve   图片主色调,算法由Camera360友情提供。  
ext   上传资源的后缀名,通过自动检测的 mimeType 或者原文件的后缀来获取。 不支持用于分片上传
uuid   生成uuid 暂不支持用于’saveKey’中
bodySha1   callbackBody的sha1(hex编码) 只支持用于’callbackUrl’中

魔法变量支持$(<Object>.<Property>)形式的访问子项,例如:

  • $(<var>)
  • $(<var>.<field_name>)
  • $(<var>.<field_name>.<sub_field_name>)

求值举例:

  • $(bucket) - 获得上传目标bucket名字
  • $(imageInfo) - 获取当前上传图片的基本属性信息
  • $(imageInfo.height) - 获取当前上传图片的原始高度

回调通知(callback)

可以设置上传策略(PutPolicy)中的callbackUrl字段,并且设置callbackBody字段。

“自定义回调”具体实现

        /// <summary>
/// 文件上传后的自定义回调
/// </summary>
/// <param name="bucket">文件所在的空间名</param>
/// <param name="key">您可以自行定义文件Key,一般GUID</param>
/// <param name="fname">文件路径+文件名</param>
public static PutRet PutFile(string bucket, string key, string fname)
{
var policy = new PutPolicy(bucket, );
policy.ReturnBody = "{\"key\": $(key), \"hash\": $(etag), \"extra\": $(x:extra), \"callbackUrl\": $(x:callbackUrl)}";
//policy.CallBackBody = "name=$(fname)&location=$(x:location)&price=$(x:price)";
//policy.CallBackUrl = "http://ip/url";
string upToken = policy.Token();
PutExtra extra = new PutExtra(); //扩展属性
Dictionary<string,string> dict =new Dictionary<string,string>();
dict.Add("x:extra", "location=shanghai&age=28");
dict.Add("x:callbackUrl", "http://127.0.0.1/callback"); extra.Params = dict;
IOClient client = new IOClient();
return client.PutFile(upToken, key, fname, extra);
}

完整源代码下载 :source code

C#使用七牛云存储上传下载文件、自定义回调的更多相关文章

  1. 七牛云存储上传自有证书开启https访问

    虽然七牛云存储也提供免费SSL证书申请,但我就喜欢用其他平台申请的,于是在腾讯云申请了免费SSL证书,正准备在七牛上传,弹出的界面却让我傻了眼,如下图所示: 腾讯免费SSL证书提供了不同服务器环境的版 ...

  2. 七牛云存储 qiniu 域名 回收 文件上传 备份 下载 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  3. 图床工具PicGO实现七牛云图片上传

    图床工具PicGO实现七牛云图片上传 我们在写博客或者网络文章时经常需要上传图片.目前最有名气的图床工具就是PicGO. 简单的界面,完整的功能,在相册里也能直接复制markdown图片链接.一直深受 ...

  4. angular封装七牛云图片上传,解决同一页面多个上传按钮分别上传

    step1:引入文件 引入Plupload *该SDK上传功能集于Plupload插件封装,所以需要下载Plupload; plupload.dev.js 引入qiniu.js为了简便,当时直接从官网 ...

  5. 七牛云覆盖上传 php

    使用七牛云过程中遇到了需要上传覆盖的情况,最终解决,分享给大家. 七牛云sdk上传示例中是这样写的 <?php require_once 'path_to_sdk/vendor/autoload ...

  6. 如何利用京东云的对象存储(OSS)上传下载文件

    作者:刘冀 在公有云厂商里都有对象存储,京东云也不例外,而且也兼容S3的标准因此可以利用相关的工具去上传下载文件,本文主要记录一下利用CloudBerry Explorer for Amazon S3 ...

  7. linux上很方便的上传下载文件工具rz和sz

    linux上很方便的上传下载文件工具rz和sz(本文适合linux入门的朋友) ##########################################################&l ...

  8. shell通过ftp实现上传/下载文件

    直接代码,shell文件名为testFtptool.sh: #!/bin/bash ########################################################## ...

  9. Servlet 上传下载文件

    上传文件 1)在表单中使用表单元素 <input type=“file” />,浏览器在解析表单时,会自动生成一个输入框和一个按钮 2)表单需要上传文件时,需指定表单 enctype 的值 ...

随机推荐

  1. oracle 查看表行数所占空间大小

    最新数据库空间有感觉捉急了,上次,删了些数据空了800+G,撑了一个多月,现在还有400+G,每天10G的增量,多少空间也感觉不够用啊. 不能加硬盘,就只有删数据了.. 删数据,人懒,直接找表行最多, ...

  2. 2018.10.25 atcoder Leftmost Ball(计数dp+组合数学)

    传送门 dp妙题啊. 我认为DZYODZYODZYO已经说的很好了. 强制规定球的排序方式. 然后就变成了一个求拓扑序数量的问题. 代码: #include<bits/stdc++.h> ...

  3. 牛客训练:小a与黄金街道(欧拉函数+快速幂)

    题目链接:传送门 思路:欧拉函数的性质:前n个数的欧拉函数之和为φ(n)*n/2,由此求出结果. 参考文章:传送门 #include<iostream> #include<cmath ...

  4. SQL中的split方法的使用

    参数说明: 1.@String :需要split的字符串 2.@Delimiter :格式化时分隔符 3.@index :返回split后数组的值 ), ),)) ) AS BEGIN )) ) DE ...

  5. Linux 安装android

    ---恢复内容开始---http://pan.baidu.com/s/1rvPP8 1.下载eclipse http://pan.baidu.com/s/1kTvNjmv http://www.cr1 ...

  6. 第27章:MongoDB-索引--唯一索引

    ①唯一索引 唯一索引的目的是为了让数据库的某个字段的值唯一,为了确保数据的都是合法的,但是唯一索引在插入数据时会对数据进行检查,一旦重复会抛出异常,效率会比较低,唯一索引只是保证数据库数据唯一的最后一 ...

  7. 关于DOM级别的一些问题,DOM0,DOM1,DOM2

    之前看书没太注意这个问题,直到我今天看书看到一个DOM0级,于是我就在群里问了下各个级别的意思区别.. 首先我们的确定标准了是没有DOM0级的.在平时阅读的时候可能会读到DOM0级(DOM Level ...

  8. python 基础_ 打印输出 循环分支2

    一.在python3中的打印输出 1.输出字符串是print("hello world!!!") #输出字符串的时候可以是单引号括起来,也可以是双引号括起来.区别在于 2.输出变量 ...

  9. 开发.Net Script 模板-MyGeneration (翻译)

    原文信息 原文地址 原文作者信息 Justin Greenwood MyGeneration Software http://www.mygenerationsoftware.com/ October ...

  10. Django-配置、静态文件与路由

    -----配置文件 1.BASE_DIR BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))   2.DEBU ...