Skip to content

Commit

Permalink
Merge pull request #45 from qiniu/develop
Browse files Browse the repository at this point in the history
Release 6.1.1
  • Loading branch information
longbai committed Apr 28, 2014
2 parents b1161e6 + aafe9e3 commit bc8d9eb
Show file tree
Hide file tree
Showing 14 changed files with 63 additions and 169 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
33 changes: 5 additions & 28 deletions Docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ DLL引用方式:
C# SDK引用了第三方的开源项目 Json.NET,因此,您需要在项目中引用它
项目地址:[http://json.codeplex.com](http://json.codeplex.com)

<a name=setup></a>
## 初始化
<a name=setup-key></a>
### 配置密钥

Expand Down Expand Up @@ -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<PutRet>((o, ret) => {
if (ret.OK)
{
Console.WriteLine("Hash: " + ret.Hash);
}
else
{
Console.WriteLine("Failed to PutFile");
}
});
client.PutFile(upToken, key, fname, extra);
}
```
Expand All @@ -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<float>((p) => {
Console.WriteLine("当前进度:{0}%", p * 100);

});
client.PutFinished += new EventHandler<CallRet>((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<PutNotifyEvent> Notify;
Expand All @@ -498,7 +475,7 @@ public event EventHandler<PutNotifyErrorEvent> NotifyErr;

其中<domain>是bucket所对应的域名。七牛云存储为每一个bucket提供一个默认域名。默认域名可以到[七牛云存储开发者平台](https://portal.qiniu.com/)中,空间设置的域名设置一节查询。用户也可以将自有的域名绑定到bucket上,用户可以通过自有域名访问七牛云存储。

**注意: key必须采用utf8编码,如使用非utf8编码访问七牛云存储将反馈错误**
**注意: key必须采用utf8编码,如使用非utf8编码访问七牛云存储将返回错误**

<a name=private-download></a>
#### 私有资源下载
Expand Down
8 changes: 0 additions & 8 deletions Qiniu.Test/IO/Resumable/ResumablePutTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<float>(target_Progress);
TmpFIle file=new TmpFIle(1024*1024*4);
target.PutFinished += new EventHandler<CallRet> ((o,e) => {
file.Del ();
Expand Down Expand Up @@ -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() + "%");
}
}
}
}
151 changes: 35 additions & 116 deletions Qiniu/IO/Resumable/ResumablePut.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
#if NET40
Expand All @@ -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

/// <summary>
/// 上传完成事件
/// </summary>
Expand All @@ -37,10 +30,6 @@ public class ResumablePut
/// 上传Failure事件
/// </summary>
public event EventHandler<CallRet> PutFailure;
/// <summary>
/// 进度提示事件
/// </summary>
public event Action<float> Progress;

Settings putSetting;

Expand Down Expand Up @@ -71,7 +60,6 @@ public ResumablePutExtra Extra
/// <param name="extra"></param>
public ResumablePut(Settings putSetting, ResumablePutExtra extra)
{
extra.chunkSize = putSetting.ChunkSize;
this.putSetting = putSetting;
this.extra = extra;
}
Expand All @@ -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)
{
Expand All @@ -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);
Expand All @@ -155,104 +122,56 @@ public CallRet PutFile(string upToken, string localFile, string key)
return ret;
}


/// <summary>
/// 百分比进度提示
/// </summary>
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<BlkputRet>(callRet.Response);
}
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<BlkputRet>(callRet.Response);
}
return null;
}

private CallRet Mkfile(Client client, string key, long fsize)
{
StringBuilder urlBuilder = new StringBuilder();
Expand Down
2 changes: 1 addition & 1 deletion Qiniu/IO/Resumable/ResumablePutRet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ public class BlkputRet
[JsonProperty("crc32")]
public UInt32 crc32;
[JsonProperty("offset")]
public UInt32 offset;
public ulong offset;
}
}
12 changes: 6 additions & 6 deletions Qiniu/IO/Resumable/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ namespace Qiniu.IO.Resumable
/// </summary>
public class Settings
{
int chunkSize;

/// <summary>
/// chunk大小,默认为4MB;
/// 兼容保留
/// </summary>
public int ChunkSize {
get { return chunkSize; }
set { chunkSize = value; }
get;
set;
}

int tryTimes;
Expand All @@ -32,8 +31,9 @@ public int TryTimes {
/// <param name="chunkSize">chunk大小,默认为4MB</param>
/// <param name="tryTimes">失败重试次数,默认为3</param>
public Settings (int chunkSize=1 << 22, int tryTimes=3)
{
this.chunkSize = chunkSize;
{
//chunkSize 已经删除,兼容保留

this.tryTimes = tryTimes;
}
}
Expand Down
3 changes: 1 addition & 2 deletions Qiniu/Qiniu.2.0.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
Expand Down Expand Up @@ -101,4 +100,4 @@
<None Include="app.config" />
</ItemGroup>
<ItemGroup />
</Project>
</Project>
2 changes: 1 addition & 1 deletion Qiniu/Qiniu.4.0.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
Expand Down
Loading

0 comments on commit bc8d9eb

Please sign in to comment.