说明
批量传输文件是在基础传输之上做的扩展功能。
使用
第一个int类参数表示同时进行的任务数量。其他参数和常规一样。
其中FileRequest、FileOperator、Metadata数量必须相等,即使Metadata为null。
static void TestMultiple()
{
TcpTouchRpcClient fileClient = CreateTcpTouchRpcClient();
Console.WriteLine("请输入文件夹路径");
string[] paths = System.IO.Directory.GetFiles(Console.ReadLine(), "*.*", System.IO.SearchOption.AllDirectories);
Console.WriteLine($"共搜索到{paths.Length}个文件,按任意键开始传输。");
Console.ReadKey();
List<FileRequest> requests = new List<FileRequest>();
List<FileOperator> fileOperators = new List<FileOperator>();
List<Metadata> metadatas = new List<Metadata>();
foreach (var item in paths)
{
FileRequest fileRequest = new FileRequest()
{
Path = item,
Overwrite = true,
SavePath = item//此处随便写,服务器会重定向保存路径。
};
metadatas.Add(null);
fileOperators.Add(new FileOperator());
requests.Add(fileRequest);
}
int num = 0;
LoopAction loopAction = LoopAction.CreateLoopAction(-1,1000,(loop)=>
{
bool fin = true;
var ops = fileOperators.ToArray();
foreach (var item in ops)
{
if (item.Result.ResultCode == ResultCode.Default)
{
fin = false;
}
else
{
Console.WriteLine($"{++num}号文件传输完成,{item.Result}");
fileOperators.Remove(item);
}
}
if (fin)
{
loop.Dispose();
Console.WriteLine("传输结束。");
}
});
loopAction.RunAsync();
fileClient.PushFilesAsync(10,requests.ToArray(),fileOperators.ToArray(),metadatas.ToArray());
Console.ReadKey();
}
原理解析
批量传输文件,其实是对单个传输的封装,封装详情请见源码。下列展示PushFiles的源码,并对其做一些解释。
当一个文件结束传输(不一定完成)时,会停顿100ms,然后再继续下个传输,这是因为涉及IO,操作系统和磁盘都不是绝对即时的,如果相邻时间太短,则容易出现问题。当然大家也可以重新按自己意愿封装。
/// <summary>
/// 批量推送文件
/// </summary>
/// <param name="client">终端</param>
/// <param name="multipleCount">并行数量</param>
/// <param name="fileRequests">批量请求头</param>
/// <param name="fileOperators">批量操作器</param>
/// <param name="metadatas">批量元数据</param>
public static void PushFiles(this IFileClientBase client, int multipleCount, FileRequest[] fileRequests, FileOperator[] fileOperators, Metadata[] metadatas)
{
if (multipleCount < 1)
{
throw new RRQMException("并行数量不能小于1。");
}
if (fileRequests is null)
{
throw new ArgumentNullException(nameof(fileRequests));
}
if (fileOperators is null)
{
throw new ArgumentNullException(nameof(fileOperators));
}
if (!(fileRequests.Length == fileOperators.Length && metadatas.Length == fileOperators.Length))
{
throw new RRQMException("FileRequest、FileOperator和Metadata数量必须一致。");
}
int index = 0;
int t = 0;
int complatedLen = 0;
List<Task<Result>> results = new List<Task<Result>>();
LoopAction loopAction = LoopAction.CreateLoopAction(-1, 100, (loop) =>
{
int st = multipleCount - t;
for (int i = 0; i < st; i++)
{
if (index == fileRequests.Length)
{
break;
}
Task<Result> result = client.PushFileAsync(fileRequests[index], fileOperators[index], metadatas[index]);
results.Add(result);
index++;
t++;
}
List<Task<Result>> cr = new List<Task<Result>>();
foreach (var item in results)
{
if (item.IsCompleted)
{
cr.Add(item);
t--;
complatedLen++;
if (complatedLen == fileRequests.Length)
{
loop.Dispose();
}
}
}
foreach (var item in cr)
{
results.Remove(item);
}
});
loopAction.Run();
}