Exemplo n.º 1
0
        /// <summary>
        /// 下载文件
        /// </summary>
        /// <param name="fileNames">需要下载的文件集合</param>
        /// <param name="mark">标记</param>
        /// <param name="saveDirectoryPath">保存路径</param>
        /// <param name="cancellationToken">异步取消命令</param>
        /// <returns>下载任务(是否成功、原因、失败文件名)</returns>
        public static async Task <TransferResult <List <string> > > FileDownload(List <string> fileNames, string mark, string saveDirectoryPath, System.Threading.CancellationToken cancellationToken = new System.Threading.CancellationToken())
        {
            var result = new TransferResult <List <string> >()
            {
                Message = $"文件保存路径不正确:{saveDirectoryPath}"
            };

            if (!System.IO.Directory.Exists(saveDirectoryPath))
            {
                return(await Task.Run(() => result));//文件路径不存在
            }
            if (fileNames.Count == 0)
            {
                result.Message = "未包含任何文件";
                return(await Task.Run(() => result));//文件路径不存在
            }
            result.Message = "未能连接到服务器";
            FileRequest request = new FileRequest()
            {
                Mark = mark
            };                                         //请求数据

            request.FileNames.AddRange(fileNames);     //将需要下载的文件名赋值
            var    lstSuccFiles = new List <string>(); //传输成功的文件
            string savePath     = string.Empty;        //保存路径

            System.IO.FileStream fs = null;
            Channel channel         = null;//申明通信频道

            GrpcService.FileTransfer.FileTransferClient client = null;
            DateTime startTime = DateTime.Now;

            try
            {
                (channel, client) = GetClient();
                using (var call = client.FileDownload(request))
                {
                    List <FileReply> lstContents = new List <FileReply>();//存放接收的数据
                    var reaponseStream           = call.ResponseStream;
                    //reaponseStream.Current.Block数字的含义是服务器和客户端约定的
                    while (await reaponseStream.MoveNext(cancellationToken))//开始接收数据
                    {
                        if (cancellationToken.IsCancellationRequested)
                        {
                            break;
                        }
                        if (reaponseStream.Current.Block == -2)//说明文件已经传输完成了
                        {
                            result.Message      = $"完成下载任务【{lstSuccFiles.Count}/{fileNames.Count}】,耗时:{DateTime.Now - startTime}";
                            result.IsSuccessful = true;
                            break;
                        }
                        else if (reaponseStream.Current.Block == -1)                          //当前文件传输错误
                        {
                            Console.WriteLine($"文件【{reaponseStream.Current.FileName}】传输失败!"); //写入日志
                            lstContents.Clear();
                            fs?.Close();                                                      //释放文件流
                            if (!string.IsNullOrEmpty(savePath) && File.Exists(savePath))     //如果传输不成功,删除该文件
                            {
                                File.Delete(savePath);
                            }
                            savePath = string.Empty;
                        }
                        else if (reaponseStream.Current.Block == 0) //当前文件传输完成
                        {
                            if (lstContents.Any())                  //如果还有数据,就写入文件
                            {
                                lstContents.OrderBy(c => c.Block).ToList().ForEach(c => c.Content.WriteTo(fs));
                                lstContents.Clear();
                            }
                            lstSuccFiles.Add(reaponseStream.Current.FileName); //传输成功的文件
                            fs?.Close();                                       //释放文件流
                            savePath = string.Empty;
                        }
                        else//有文件数据过来
                        {
                            if (string.IsNullOrEmpty(savePath))//如果字节流为空,则说明时新的文件数据来了
                            {
                                savePath = Path.Combine(saveDirectoryPath, reaponseStream.Current.FileName);
                                fs       = new FileStream(savePath, FileMode.Create, FileAccess.ReadWrite);
                            }
                            lstContents.Add(reaponseStream.Current); //加入链表
                            if (lstContents.Count() >= 20)           //每个包1M,20M为一个集合,一起写入数据。
                            {
                                lstContents.OrderBy(c => c.Block).ToList().ForEach(c => c.Content.WriteTo(fs));
                                lstContents.Clear();
                            }
                        }
                    }
                }
                fs?.Close();                                                                          //释放文件流
                if (!result.IsSuccessful && !string.IsNullOrEmpty(savePath) && File.Exists(savePath)) //如果传输不成功,那么久删除该文件
                {
                    File.Delete(savePath);
                }
            }
            catch (Exception ex)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    fs?.Close();//释放文件流
                    result.IsSuccessful = false;
                    result.Message      = $"用户取消下载。已完成下载【{lstSuccFiles.Count}/{fileNames.Count}】,耗时:{DateTime.Now - startTime}";
                }
                else
                {
                    result.Message = $"文件传输发生异常:{ex.Message}";
                }
            }
            finally
            {
                fs?.Dispose();
            }
            result.Tag = fileNames.Except(lstSuccFiles).ToList();//获取失败文件集合
            //关闭通信、并返回结果
            return(await channel?.ShutdownAsync().ContinueWith(t => result));
        }
Exemplo n.º 2
0
        /// <summary>
        /// 文件上传
        /// </summary>
        /// <param name="filesPath">文件路径</param>
        /// <param name="mark">标记</param>
        /// <param name="cancellationToken">异步取消命令</param>
        /// <returns>下载任务(是否成功、原因、成功的文件名)</returns>
        public static async Task <TransferResult <List <string> > > FileUpload(List <string> filesPath, string mark, System.Threading.CancellationToken cancellationToken = new System.Threading.CancellationToken())
        {
            var result = new TransferResult <List <string> > {
                Message = "没有文件需要下载"
            };

            if (filesPath.Count == 0)
            {
                return(await Task.Run(() => result));//没有文件需要下载
            }
            result.Message = "未能连接到服务器。";
            var lstSuccFiles = new List <string>();//传输成功的文件
            int chunkSize    = 1024 * 1024;

            byte[]     buffer  = new byte[chunkSize]; //每次发送的大小
            FileStream fs      = null;                //文件流
            Channel    channel = null;                //申明通信频道

            GrpcService.FileTransfer.FileTransferClient client = null;
            DateTime startTime = DateTime.Now;

            try
            {
                (channel, client) = GetClient();
                using (var stream = client.FileUpload())//连接上传文件的客户端
                {
                    //reply.Block数字的含义是服务器和客户端约定的
                    foreach (var filePath in filesPath)//遍历集合
                    {
                        if (cancellationToken.IsCancellationRequested)
                        {
                            break;//取消了传输
                        }
                        FileReply reply = new FileReply()
                        {
                            FileName = Path.GetFileName(filePath),
                            Mark     = mark
                        };
                        if (!File.Exists(filePath))                 //文件不存在,继续下一轮的发送
                        {
                            Console.WriteLine($"文件不存在:{filePath}"); //写入日志
                            continue;
                        }
                        fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, chunkSize, useAsync: true);
                        int readTimes = 0;
                        while (true)
                        {
                            if (cancellationToken.IsCancellationRequested)
                            {
                                reply.Block   = -1;                           //取消了传输
                                reply.Content = Google.Protobuf.ByteString.Empty;
                                await stream.RequestStream.WriteAsync(reply); //发送取消传输的命令

                                break;                                        //取消了传输
                            }
                            int readSize = fs.Read(buffer, 0, buffer.Length); //读取数据
                            if (readSize > 0)
                            {
                                reply.Block   = ++readTimes;//更新标记,发送数据
                                reply.Content = Google.Protobuf.ByteString.CopyFrom(buffer, 0, readSize);
                                await stream.RequestStream.WriteAsync(reply);
                            }
                            else
                            {
                                Console.WriteLine($"完成文件【{filePath}】的上传。");
                                reply.Block   = 0;                            //传送本次文件发送结束的标记
                                reply.Content = Google.Protobuf.ByteString.Empty;
                                await stream.RequestStream.WriteAsync(reply); //发送结束标记

                                //等待服务器回传
                                await stream.ResponseStream.MoveNext(cancellationToken);

                                if (stream.ResponseStream.Current != null && stream.ResponseStream.Current.Mark == mark)
                                {
                                    lstSuccFiles.Add(filePath); //记录成功的文件
                                }
                                break;                          //发送下一个文件
                            }
                        }
                        fs?.Close();
                    }
                    if (!cancellationToken.IsCancellationRequested)
                    {
                        result.IsSuccessful = true;
                        result.Message      = $"完成文件上传。共计【{lstSuccFiles.Count}/{filesPath.Count}】,耗时:{DateTime.Now - startTime}";

                        await stream.RequestStream.WriteAsync(new FileReply
                        {
                            Block = -2, //传输结束
                            Mark  = mark
                        });             //发送结束标记
                    }
                }
            }
            catch (Exception ex)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    fs?.Close();//释放文件流
                    result.IsSuccessful = false;
                    result.Message      = $"用户取消了上传文件。已完成【{lstSuccFiles.Count}/{filesPath.Count}】,耗时:{DateTime.Now - startTime}";
                }
                else
                {
                    result.Message = $"文件上传发生异常({ex.GetType()}):{ex.Message}";
                }
            }
            finally
            {
                fs?.Dispose();
            }
            Console.WriteLine(result.Message);
            result.Tag = lstSuccFiles;
            //关闭通信、并返回结果
            return(await channel?.ShutdownAsync().ContinueWith(t => result));
        }