diff --git a/CHANGELOG.md b/CHANGELOG.md
index df7c3fb6..53bd8c56 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
## CHANGE LOG
+### v6.1.1
+2014-04-28 issue [#45](https://github.com/qiniu/csharp-sdk/pull/45)
+- [#41] [#42] 简化断点续上传,删除bput逻辑, 修复bug:>2.5GB文件上传失败
+- [#38] [#40] pfop 支持
+
### v6.1.0
2014-02-18 issue [#37](https://github.com/qiniu/csharp-sdk/pull/37)
diff --git a/Docs/README.md b/Docs/README.md
index 407ad2bf..909c62e5 100644
--- a/Docs/README.md
+++ b/Docs/README.md
@@ -58,6 +58,8 @@ DLL引用方式:
C# SDK引用了第三方的开源项目 Json.NET,因此,您需要在项目中引用它
项目地址:[http://json.codeplex.com](http://json.codeplex.com)。
+
+## 初始化
### 配置密钥
@@ -424,18 +426,8 @@ public static void PutFile(string bucket, string key, string fname)
{
var policy = new PutPolicy(bucket, 3600);
string upToken = policy.Token();
- PutExtra extra = new PutExtra { Bucket = bucket };
+ PutExtra extra = new PutExtra ();
IOClient client = new IOClient();
- client.PutFinished += new EventHandler((o, ret) => {
- if (ret.OK)
- {
- Console.WriteLine("Hash: " + ret.Hash);
- }
- else
- {
- Console.WriteLine("Failed to PutFile");
- }
- });
client.PutFile(upToken, key, fname, extra);
}
```
@@ -455,27 +447,12 @@ public static void ResumablePutFile(string bucket, string key, string fname)
string upToken = policy.Token();
Settings setting = new Settings();
ResumablePutExtra extra = new ResumablePutExtra();
- extra.Bucket = bucket;
ResumablePut client = new ResumablePut(setting, extra);
- client.Progress += new Action((p) => {
- Console.WriteLine("当前进度:{0}%", p * 100);
-
- });
- client.PutFinished += new EventHandler((o, ret) => {
- if (ret.OK)
- {
- Console.WriteLine("上传成功:{0}",ret.Response);
- }
- else
- {
- Console.WriteLine("上传失败:{0}", ret.Response);
- }
- });
client.PutFile(upToken, fname, Guid.NewGuid().ToString());
}
```
-ResumablePut采用分快上传,各快之间采用并行上传,通过注册事件Progress可以获取当前文件上传进度,同时您也可以通过注册ResumablePutExtra以下两个事件监听当前上传进度以及成功情况:
+ResumablePut采用分快上传,各快之间采用并行上传,可以通过注册ResumablePutExtra以下两个事件监听当前上传进度以及成功情况:
```c#
public event EventHandler Notify;
@@ -498,7 +475,7 @@ public event EventHandler NotifyErr;
其中是bucket所对应的域名。七牛云存储为每一个bucket提供一个默认域名。默认域名可以到[七牛云存储开发者平台](https://portal.qiniu.com/)中,空间设置的域名设置一节查询。用户也可以将自有的域名绑定到bucket上,用户可以通过自有域名访问七牛云存储。
-**注意: key必须采用utf8编码,如使用非utf8编码访问七牛云存储将反馈错误**
+**注意: key必须采用utf8编码,如使用非utf8编码访问七牛云存储将返回错误**
#### 私有资源下载
diff --git a/Qiniu.Test/IO/Resumable/ResumablePutTest.cs b/Qiniu.Test/IO/Resumable/ResumablePutTest.cs
index 2de68ba1..7a472060 100644
--- a/Qiniu.Test/IO/Resumable/ResumablePutTest.cs
+++ b/Qiniu.Test/IO/Resumable/ResumablePutTest.cs
@@ -34,7 +34,6 @@ public void ResumablePutFileTest()
ResumablePut target = new ResumablePut(putSetting, extra); // TODO: 初始化为适当的值
Console.WriteLine ("extra.Bucket:"+Bucket);
string upToken = new PutPolicy(Bucket).Token(new Qiniu.Auth.digest.Mac());
- target.Progress += new Action(target_Progress);
TmpFIle file=new TmpFIle(1024*1024*4);
target.PutFinished += new EventHandler ((o,e) => {
file.Del ();
@@ -63,12 +62,5 @@ void extra_Notify(object sender, PutNotifyEvent e)
PrintLn(e.BlkSize.ToString());
PrintLn(e.Ret.offset.ToString());
}
- void target_Progress(float obj)
- {
- if (obj > 0.999999)
- {
- PrintLn((obj * 100).ToString() + "%");
- }
- }
}
}
diff --git a/Qiniu/IO/Resumable/ResumablePut.cs b/Qiniu/IO/Resumable/ResumablePut.cs
index 22893e0a..b6ed3777 100644
--- a/Qiniu/IO/Resumable/ResumablePut.cs
+++ b/Qiniu/IO/Resumable/ResumablePut.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.IO;
using System.Text;
#if NET40
@@ -21,14 +22,6 @@ public class ResumablePut
private const int blockMashk = (1 << blockBits) - 1;
private static int BLOCKSIZE = 4 * 1024 * 1024;
- #region 记录总文件大小,用于计算上传百分比
-
- private long fsize;
- private float chunks;
- private float uploadedChunks = 0;
-
- #endregion
-
///
/// 上传完成事件
///
@@ -37,10 +30,6 @@ public class ResumablePut
/// 上传Failure事件
///
public event EventHandler PutFailure;
- ///
- /// 进度提示事件
- ///
- public event Action Progress;
Settings putSetting;
@@ -71,7 +60,6 @@ public ResumablePutExtra Extra
///
public ResumablePut(Settings putSetting, ResumablePutExtra extra)
{
- extra.chunkSize = putSetting.ChunkSize;
this.putSetting = putSetting;
this.extra = extra;
}
@@ -88,36 +76,23 @@ public CallRet PutFile(string upToken, string localFile, string key)
{
throw new Exception(string.Format("{0} does not exist", localFile));
}
+
PutAuthClient client = new PutAuthClient(upToken);
CallRet ret;
using (FileStream fs = File.OpenRead(localFile))
{
int block_cnt = block_count(fs.Length);
- fsize = fs.Length;
- chunks = fsize / extra.chunkSize + 1;
+ long fsize = fs.Length;
extra.Progresses = new BlkputRet[block_cnt];
- //并行上传
-#if NET35||NET20
+ byte[] byteBuf = new byte[BLOCKSIZE];
+ int readLen = BLOCKSIZE;
for (int i = 0; i < block_cnt; i++)
{
-#elif NET40
- Parallel.For(0, block_cnt, (i) =>{
-#endif
-
- int readLen = BLOCKSIZE;
- if ((i + 1) * BLOCKSIZE > fsize)
- readLen = (int)(fsize - i * BLOCKSIZE);
- byte[] byteBuf = new byte[readLen];
-#if NET40
- lock (fs)
- {
-#endif
- fs.Seek(i * BLOCKSIZE, SeekOrigin.Begin);
+ if (i == block_cnt - 1) {
+ readLen = (int)(fsize - (long)i * BLOCKSIZE);
+ }
+ fs.Seek((long)i * BLOCKSIZE, SeekOrigin.Begin);
fs.Read(byteBuf, 0, readLen);
-#if NET40
- }
-#endif
- //并行上传BLOCK
BlkputRet blkRet = ResumableBlockPut(client, byteBuf, i, readLen);
if (blkRet == null)
{
@@ -127,19 +102,11 @@ public CallRet PutFile(string upToken, string localFile, string key)
{
extra.OnNotify(new PutNotifyEvent(i, readLen, extra.Progresses[i]));
}
-#if NET35||NET20
}
-#elif NET40
- });
-#endif
- ret = Mkfile(client, key, fs.Length);
+ ret = Mkfile(client, key, fsize);
}
if (ret.OK)
{
- if (Progress != null)
- {
- Progress(1.0f);
- }
if (PutFinished != null)
{
PutFinished(this, ret);
@@ -155,86 +122,49 @@ public CallRet PutFile(string upToken, string localFile, string key)
return ret;
}
-
- ///
- /// 百分比进度提示
- ///
- private void progress()
- {
- uploadedChunks++;
- if (Progress != null)
- {
- Progress((float)uploadedChunks / chunks);
- }
- }
-
private BlkputRet ResumableBlockPut(Client client, byte[] body, int blkIdex, int blkSize)
{
- int bodyLength;
- int chunkSize = extra.chunkSize;
#region Mkblock
- if (extra.Progresses[blkIdex] == null)
+ uint crc32 = CRC32.CheckSumBytes(body, blkSize);
+ for (int i = 0; i < putSetting.TryTimes; i++)
{
- bodyLength = chunkSize < blkSize ? chunkSize : blkSize;
- byte[] firstChunk = new byte[bodyLength];
- Array.Copy(body, 0, firstChunk, 0, bodyLength);
- uint crc32 = CRC32.CheckSumBytes(firstChunk);
- for (int i = 0; i < putSetting.TryTimes; i++)
+ try
{
- extra.Progresses[blkIdex] = Mkblock(client, firstChunk, body.Length);
- if (extra.Progresses[blkIdex] == null || crc32 != extra.Progresses[blkIdex].crc32)
- {
- if (i == (putSetting.TryTimes - 1))
- {
- return null;
- }
- continue;
- }
- else
- {
- progress();
- break;
- }
+ extra.Progresses[blkIdex] = Mkblock(client, body, blkSize);
}
- }
- #endregion
-
- #region PutBlock
- while (extra.Progresses[blkIdex].offset < blkSize)
- {
- bodyLength = (chunkSize < (blkSize - extra.Progresses[blkIdex].offset)) ? chunkSize : (int)(blkSize - extra.Progresses[blkIdex].offset);
- byte[] chunk = new byte[bodyLength];
- Array.Copy(body, extra.Progresses[blkIdex].offset, chunk, 0, bodyLength);
- for (int i = 0; i < putSetting.TryTimes; i++)
+ catch (Exception ee)
{
- extra.Progresses[blkIdex] = BlockPut(client, extra.Progresses[blkIdex], new MemoryStream(chunk), bodyLength);
- if (extra.Progresses[blkIdex] == null)
+ if (i == (putSetting.TryTimes - 1))
{
- if (i == (putSetting.TryTimes - 1))
- {
- return null;
- }
- continue;
+ throw ee;
}
- else
+ System.Threading.Thread.Sleep(1000);
+ continue;
+ }
+ if (extra.Progresses[blkIdex] == null || crc32 != extra.Progresses[blkIdex].crc32)
+ {
+ if (i == (putSetting.TryTimes - 1))
{
- uploadedChunks++;
- if (Progress != null)
- {
- Progress((float)uploadedChunks / chunks);
- }
- break;
+ return null;
}
+ System.Threading.Thread.Sleep(1000);
+ continue;
+ }
+ else
+ {
+ break;
}
}
#endregion
+
return extra.Progresses[blkIdex];
- }
+ }
- private BlkputRet Mkblock(Client client, byte[] firstChunk, long blkSize)
+ private BlkputRet Mkblock(Client client, byte[] firstChunk, int blkSize)
{
string url = string.Format("{0}/mkblk/{1}", Config.UP_HOST, blkSize);
- CallRet callRet = client.CallWithBinary(url, "application/octet-stream", new MemoryStream(firstChunk), firstChunk.Length);
+
+ CallRet callRet = client.CallWithBinary(url, "application/octet-stream",new MemoryStream(firstChunk, 0, blkSize),blkSize);
if (callRet.OK)
{
return QiniuJsonHelper.ToObject(callRet.Response);
@@ -242,17 +172,6 @@ private BlkputRet Mkblock(Client client, byte[] firstChunk, long blkSize)
return null;
}
- private BlkputRet BlockPut(Client client, BlkputRet ret, Stream body, long length)
- {
- string url = string.Format("{0}/bput/{1}/{2}", Config.UP_HOST, ret.ctx, ret.offset);
- CallRet callRet = client.CallWithBinary(url, "application/octet-stream", body, length);
- if (callRet.OK)
- {
- return QiniuJsonHelper.ToObject(callRet.Response);
- }
- return null;
- }
-
private CallRet Mkfile(Client client, string key, long fsize)
{
StringBuilder urlBuilder = new StringBuilder();
diff --git a/Qiniu/IO/Resumable/ResumablePutRet.cs b/Qiniu/IO/Resumable/ResumablePutRet.cs
index e7dfa6d0..a04828e2 100644
--- a/Qiniu/IO/Resumable/ResumablePutRet.cs
+++ b/Qiniu/IO/Resumable/ResumablePutRet.cs
@@ -13,6 +13,6 @@ public class BlkputRet
[JsonProperty("crc32")]
public UInt32 crc32;
[JsonProperty("offset")]
- public UInt32 offset;
+ public ulong offset;
}
}
diff --git a/Qiniu/IO/Resumable/Settings.cs b/Qiniu/IO/Resumable/Settings.cs
index 63331210..e439950b 100644
--- a/Qiniu/IO/Resumable/Settings.cs
+++ b/Qiniu/IO/Resumable/Settings.cs
@@ -6,14 +6,13 @@ namespace Qiniu.IO.Resumable
///
public class Settings
{
- int chunkSize;
-
///
/// chunk大小,默认为4MB;
+ /// 兼容保留
///
public int ChunkSize {
- get { return chunkSize; }
- set { chunkSize = value; }
+ get;
+ set;
}
int tryTimes;
@@ -32,8 +31,9 @@ public int TryTimes {
/// chunk大小,默认为4MB
/// 失败重试次数,默认为3
public Settings (int chunkSize=1 << 22, int tryTimes=3)
- {
- this.chunkSize = chunkSize;
+ {
+ //chunkSize 已经删除,兼容保留
+
this.tryTimes = tryTimes;
}
}
diff --git a/Qiniu/Qiniu.2.0.csproj b/Qiniu/Qiniu.2.0.csproj
index 00539836..f38ad126 100644
--- a/Qiniu/Qiniu.2.0.csproj
+++ b/Qiniu/Qiniu.2.0.csproj
@@ -15,7 +15,6 @@
- x86
true
full
false
@@ -101,4 +100,4 @@
-
\ No newline at end of file
+
diff --git a/Qiniu/Qiniu.4.0.csproj b/Qiniu/Qiniu.4.0.csproj
index 1734a9af..0535cc75 100644
--- a/Qiniu/Qiniu.4.0.csproj
+++ b/Qiniu/Qiniu.4.0.csproj
@@ -15,7 +15,7 @@
- x86
+ AnyCPU
true
full
false
diff --git a/Qiniu/Util/CRC32.cs b/Qiniu/Util/CRC32.cs
index 01ea3786..e8c638a9 100644
--- a/Qiniu/Util/CRC32.cs
+++ b/Qiniu/Util/CRC32.cs
@@ -50,10 +50,10 @@ public static UInt32 Update (UInt32 crc, UInt32[] table, byte[] p, int offset, i
return ~crc;
}
- public static UInt32 CheckSumBytes (byte[] data)
+ public static UInt32 CheckSumBytes (byte[] data,int length)
{
CRC32 crc = new CRC32 ();
- crc.Write (data, 0, data.Length);
+ crc.Write (data, 0, length);
return crc.Sum32 ();
}
diff --git a/README.md b/README.md
index 0c9be7a4..b50a66aa 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
# Qiniu Resource (Cloud) Storage SDK for C#
+[](https://travis-ci.org/qiniu/csharp-sdk)
+
# 关于
此 C# SDK 适用于 .NET2.0 及以上版本,基于 [七牛云存储官方API](http://developer.qiniu.com/docs/v6/api/) 构建。使用此 SDK 构建您的网络应用程序,能让您以非常便捷地方式将数据安全地存储到七牛云存储上。无论您的网络应用是一个网站程序,还是包括从云端(服务端程序)到终端(手持设备应用)的架构的服务或应用,通过七牛云存储及其 SDK,都能让您应用程序的终端用户高速上传和下载,同时也让您的服务端更加轻盈。
@@ -18,7 +20,7 @@
## 许可证
-Copyright (c) 2012 qiniutek.com
+Copyright (c) 2014 qiniu.com
基于 MIT 协议发布:
diff --git a/bin/Qiniu.2.0.dll b/bin/Qiniu.2.0.dll
new file mode 100755
index 00000000..92cd6bae
Binary files /dev/null and b/bin/Qiniu.2.0.dll differ
diff --git a/bin/Qiniu.4.0.dll b/bin/Qiniu.4.0.dll
index 3263456b..a0595c76 100755
Binary files a/bin/Qiniu.4.0.dll and b/bin/Qiniu.4.0.dll differ
diff --git a/csharp-sdk.2.0.sln b/csharp-sdk.2.0.sln
index f374e292..d3f062ea 100644
--- a/csharp-sdk.2.0.sln
+++ b/csharp-sdk.2.0.sln
@@ -3,9 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SDK", "SDK", "{65603FA4-DDC3-4FD7-ADA3-7BCC2161A247}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qiniu", "Qiniu\Qiniu.2.0.csproj", "{AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qiniu.2.0", "Qiniu\Qiniu.2.0.csproj", "{AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qiniu.Test", "Qiniu.Test\Qiniu.2.0.Test.csproj", "{95DC2A77-2344-4315-9F6F-334CC928459C}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qiniu.2.0.Test", "Qiniu.Test\Qiniu.2.0.Test.csproj", "{95DC2A77-2344-4315-9F6F-334CC928459C}"
EndProject
Global
GlobalSection(TestCaseManagementSettings) = postSolution
diff --git a/csharp-sdk.4.0.sln b/csharp-sdk.4.0.sln
index a98455bc..7d25e03f 100644
--- a/csharp-sdk.4.0.sln
+++ b/csharp-sdk.4.0.sln
@@ -3,9 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SDK", "SDK", "{65603FA4-DDC3-4FD7-ADA3-7BCC2161A247}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qiniu", "Qiniu\Qiniu.4.0.csproj", "{AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qiniu.4.0", "Qiniu\Qiniu.4.0.csproj", "{AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qiniu.Test", "Qiniu.Test\Qiniu.4.0.Test.csproj", "{95DC2A77-2344-4315-9F6F-334CC928459C}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qiniu.4.0.Test", "Qiniu.Test\Qiniu.4.0.Test.csproj", "{95DC2A77-2344-4315-9F6F-334CC928459C}"
EndProject
Global
GlobalSection(TestCaseManagementSettings) = postSolution