• WebApi 文件上传,断点上传,分块上传,断点下载,查询 (图片的直接预览,视频边加载边播放)


    using Manjinba.Communication.Common.Caching;
    using Manjinba.Communication.Common.Logging;
    using Manjinba.Communication.Common.Utils;
    using Manjinba.Communication.IRepository;
    using Manjinba.Communication.IService;
    using Manjinba.Communication.Model;
    using Manjinba.Communication.Model.ConstVals;
    using Manjinba.Communication.Model.Enums;
    using Manjinba.Communication.Model.Response;
    using Manjinba.Communication.Service.Caching;
    using Manjinba.Communication.WebApiFtp.Attributes;
    using Manjinba.Communication.WebApiFtp.Provider;
    using Manjinba.Communication.WebApiFtp.Resources;
    using Microsoft.Practices.Unity;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Net.Http.Headers;
    using System.Security.Cryptography;
    using System.Text;
    using System.Threading.Tasks;
    using System.Web;
    using System.Web.Http;
    using System.Web.Http.Results;

    namespace Manjinba.Communication.WebApiFtp.Controllers.V1_5
    {
    /// <summary>
    ///
    /// </summary>
    //[RoutePrefix("api/v1.4/fileoperator")]
    public class FileOperatorController : ApiController
    {
    /// <summary>
    /// 文件仓储层
    /// </summary>
    [Dependency]
    public IFileGuideRepository fileRepository { get; set; }
    /// <summary>
    /// 文件操作服务
    /// </summary>
    [Dependency]
    public IFileOperatorService fileOperatorService { get; set; }

    #region 配置文件参数
    /// <summary>
    /// 缓存配置
    /// </summary>
    private readonly string cacheTime = ConfigUtil.GetConfigStr("Cache-Control");
    /// <summary>
    /// 上传文件最大大小
    /// </summary>
    private readonly int maxSizeUploadFile = ConfigUtil.GetConfigInt("maxSizeUploadFile") == 0 ? 104857600 : ConfigUtil.GetConfigInt("maxSizeUploadFile");
    /// <summary>
    /// ftp服务节点名
    /// </summary>
    private readonly string ftpServerNodeName = ConfigUtil.GetConfigStr("FtpServerNodeName");
    /// <summary>
    /// 文件MD5缓存过期小时数
    /// </summary>
    private readonly string ftpFileCacheExpireHour = ConfigUtil.GetConfigStr("FtpFileCacheExpireHour");
    /// <summary>
    /// 聊天文件失效时间(小时)
    /// </summary>
    private readonly string chatFileExpireHour = ConfigUtil.GetConfigStr("ChatFileExpireHour");
    /// <summary>
    /// 分块文件失效时间(小时)
    /// </summary>
    private readonly string blockFileExpireHour = ConfigUtil.GetConfigStr("BlockFileExpireHour");
    /// <summary>
    /// 断点续传文件失效时间(小时)
    /// </summary>
    private readonly string breakResumeFileExpireHour = ConfigUtil.GetConfigStr("BreakResumeFileExpireHour");
    /// <summary>
    /// 日期格式路径
    /// </summary>
    private readonly string dateTimePath = DateTime.Now.Year.ToString().PadLeft(2, '0')
    + "/" + DateTime.Now.Month.ToString().PadLeft(2, '0')
    + "/" + DateTime.Now.Day.ToString().PadLeft(2, '0');
    /// <summary>
    /// 合并后是否删除分块文件
    /// </summary>
    private readonly bool? isCombineDelete = ConfigUtil.GetConfigStr("IsCombineDelete")?.ToBool();
    /// <summary>
    /// FTP根路径
    /// </summary>
    private readonly string ftprootpath = ConfigUtil.GetConfigStr("RootFtpPath").TrimStart('/').TrimEnd('/');
    #endregion

    #region 文件上传
    /// <summary>
    /// 多文件上传(流方式)上传文件根据上传文件类型进行区分
    /// </summary>
    /// <returns></returns>
    [IgnoreRequestStreamLog]
    //[HttpPost, Route("UploadFile")]
    [HttpPost]
    public async Task<JsonResult<UploadResponse>> UploadFile()
    {
    // Check whether the POST operation is MultiPart?
    if (!Request.Content.IsMimeMultipartContent("form-data"))
    {
    throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
    }
    var response = new UploadResponse
    {
    uploadResult = new List<FileUploadResult>(),
    // 文件保存失败
    code = (int)FileOperatorStatusCode.SaveFileDefeated,
    error = FileOperatorStatusCode.SaveFileDefeated.GetEnumText()
    };
    #region 取流文件,然后决定是否保存文件至Ftp
    var provider = new MultipartFormDataMemoryStreamProvider();
    // Read the form and file data.
    UploadResponse uploadResponse = await Request.Content.ReadAsMultipartAsync(provider)
    .ContinueWith(o =>
    {
    try
    {
    var isRangeRequest = false;
    long? startPosition = null;
    long? endPosition = null;
    var rangeFileCode = string.Empty;
    if (Request.Headers.Range != null && Request.Headers.Range.Ranges.Count > 0)
    {
    isRangeRequest = true;
    RangeItemHeaderValue range = Request.Headers.Range.Ranges.First();
    startPosition = range.From.HasValue ? range.From : null;
    endPosition = range.To.HasValue ? range.To : null;
    }
    // This illustrates how to get the file names.
    foreach (MultipartFileData file in provider.FileData)
    {
    var fileUploadResult = new FileUploadResult();
    //接收文件及输出上传文件类型
    var oldFileName = file.Headers.ContentDisposition.FileName.Trim('"'); // 获取上传文件实际的文件名
    var fileExt = oldFileName.Substring(oldFileName.LastIndexOf('.') + 1)?.ToLower();
    int businessType = 0;//上传文件业务类型
    if (!provider.FormData.AllKeys.Any(a => a.Equals("businessType", StringComparison.CurrentCultureIgnoreCase)))
    {
    response.code = -(int)FileOperatorStatusCode.ParameterError;
    response.error = "请求参数错误,请求参数不包含业务类型信息!";
    return response;
    }
    else
    {
    var businessTypeKey = provider.FormData.GetValues(
    provider.FormData.AllKeys.Where(w => w.Equals("businessType", StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault()
    ).FirstOrDefault();
    Int32.TryParse(businessTypeKey, out businessType);//从表单中获取到上传文件业务类型,输出赋值给busnissType
    }
    fileUploadResult.fileName = oldFileName;
    #region 检查扩展名黑白名单
    if (string.IsNullOrWhiteSpace(fileExt) || !FileExtensionUtil.IsWhiteContains(fileExt) || FileExtensionUtil.IsBlackContains(fileExt))
    {
    fileOperatorService.SetErrorResponse(response, fileUploadResult, FileOperatorStatusCode.NotSupportType);//不支持文件上传类型
    continue;
    }
    #endregion
    if (isRangeRequest)
    {
    if (!provider.FormData.AllKeys.Any(a => a.Equals("fileCode", StringComparison.CurrentCultureIgnoreCase)))
    {
    response.code = -(int)FileOperatorStatusCode.ParameterError;
    response.error = "请求参数错误,不包含断点续传文件唯一信息";
    return response;
    }
    else
    {
    rangeFileCode = provider.FormData.GetValues(
    provider.FormData.AllKeys.Where(w => w.Equals("fileCode", StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault()
    ).FirstOrDefault();
    if (rangeFileCode.Contains("."))
    {
    rangeFileCode = rangeFileCode.Substring(0, rangeFileCode.LastIndexOf('.'));
    }
    }
    }
    using (var stream = ((MultipartFileDataStream)file).Stream)
    {
    #region 检查文件大小
    var fileLength = (long)0;
    try
    {
    fileLength = stream.Length;
    }
    catch (ObjectDisposedException ode)
    {
    LogHelper.GetLog().Error(ode.Message + ode.StackTrace);
    response.code = -(int)FileOperatorStatusCode.ObjectDisposed;
    response.error = "请求参数错误,请求参数不包含业务类型信息!";
    return response;
    }
    // 最大文件大小
    if (fileLength <= 0)
    {
    fileOperatorService.SetErrorResponse(response, fileUploadResult, FileOperatorStatusCode.NotExist);
    continue;
    }
    else if (fileLength > maxSizeUploadFile)
    {
    fileOperatorService.SetErrorResponse(response, fileUploadResult, FileOperatorStatusCode.OverSize);
    continue;
    }
    #endregion

    #region 根据文件内容MD5查询文件是否已存在
    var fileContentMD5 = isRangeRequest ? rangeFileCode : FileMD5HashCodeUtil.GetFileContentMD5HashCode(stream);//获取文件流生成MD5文件
    var fileMd5Name = fileContentMD5 + "." + fileExt;
    fileUploadResult.fileCode = fileMd5Name;
    fileUploadResult.fileType = fileExt;
    fileUploadResult.fileBusinessType = businessType;
    var oldFilePath = string.Empty;
    var fileMd5IsExist = fileOperatorService.CheckFileIsExist(fileMd5Name, businessType, out oldFilePath);
    if (fileMd5IsExist)
    {
    fileOperatorService.SetSuccessResponse(response, fileUploadResult, FileOperatorStatusCode.AlreadyExists);
    continue;
    }
    // 断点续传
    if (isRangeRequest)
    {
    var breakFilePath = string.Empty;
    var breakFileSize = (long)0;
    var breakResumeMd5IsExist = fileOperatorService.CheckBreakResumeFileIsExist(fileMd5Name, businessType, out breakFilePath);
    if (breakResumeMd5IsExist && !string.IsNullOrWhiteSpace(breakFilePath))
    {
    breakFileSize = FtpOperationUtil.GetFileSize(ExchangeFilePath(breakFilePath) + "/" + fileMd5Name);
    }
    if (startPosition != breakFileSize)
    {
    response.code = -(int)FileOperatorStatusCode.StartPositionError;
    response.error = FileOperatorStatusCode.StartPositionError.GetEnumText();
    return response;
    }
    }
    #endregion

    #region Ftp操作 上传Ftp
    if (!fileMd5IsExist)
    {
    #region 上传Ftp服务器
    // 获取完整存储路径(不含 ftp:// serverip)
    var filePath = fileOperatorService.SaveFileToFtp(stream, fileMd5Name, FtpOperationUtil.GetFileDefaultPath(((BusinessFileType)businessType).ToString()));//数据流保存到FTP
    stream.Position = 0;
    if (string.IsNullOrEmpty(filePath))
    {
    LogHelper.GetLog(this).Error("返回路径为空");
    fileOperatorService.SetErrorResponse(response, fileUploadResult, FileOperatorStatusCode.SaveFileDefeated);
    continue;
    }
    // 判断文件是否完整
    var isFileComplete = false;
    if (isRangeRequest)
    {
    isFileComplete = FtpOperationUtil.CheckFileIsComplete(ExchangeFilePath(filePath) + "/" + fileMd5Name);
    }
    //var breakResumeFileSize = FtpOperationUtil.GetFileSize(ExchangeFilePath(filePath) + "/" + fileMd5Name);
    #endregion

    #region 不存在则存入内容MD5缓存
    // Ftp文件信息
    FtpFile ftpFile = new FtpFile();
    ftpFile = new FtpFile
    {
    fileName = oldFileName,
    businessType = businessType, //上传文件业务类型
    nodeName = ftpServerNodeName,
    filePath = filePath,
    fileCode = fileMd5Name,
    fileType = fileExt//,
    //fileSize = breakResumeFileSize
    };
    var fileCodeKey = string.Empty;
    var expireHour = string.Empty;
    int fileExpireHour = 0;
    // 不是断点续传 或 断点续传完成
    if (!isRangeRequest || isFileComplete)
    {
    if ((BusinessFileType)businessType != BusinessFileType.ChatFile)
    {
    // 先写入数据库
    var dbResult = fileOperatorService.AddFile(businessType, oldFileName, fileMd5Name, filePath);//添加文件信息
    if (!dbResult)
    {
    LogHelper.GetLog(this).Error("写入数据库失败");
    fileOperatorService.SetErrorResponse(response, fileUploadResult, FileOperatorStatusCode.DbSaveFileDefeated);
    continue;
    }
    expireHour = chatFileExpireHour;
    }
    else
    {
    expireHour = ftpFileCacheExpireHour;
    }
    int.TryParse(expireHour, out fileExpireHour);
    if (fileExpireHour == 0)
    {
    fileExpireHour = 24;
    }
    //fileCodeKey = (ConstVal.foreverFilePre + businessType + ":" + fileMd5Name).ToUpper();
    fileCodeKey = (ConstVal.foreverFilePre + fileMd5Name).ToUpper();
    fileOperatorService.AddToCache(fileCodeKey, ftpFile, fileExpireHour);
    LogHelper.GetLog(this).DebugFormat("写入内容MD5缓存:filename:'{0}', fileContentMD5:'{1}'", oldFileName, fileMd5Name);
    fileOperatorService.SetSuccessResponse(response, fileUploadResult, FileOperatorStatusCode.SaveSuccess);
    response.code = 0;
    response.error = string.Empty;
    // 如果是断点并上传完成,删除断点缓存
    if (isRangeRequest && isFileComplete)
    {
    //var breakKey = (ConstVal.breakResumeFilePre + businessType + ":" + fileMd5Name).ToUpper();
    var breakKey = (ConstVal.breakResumeFilePre + fileMd5Name).ToUpper();
    using (var cache = new StackExchangeRedis())
    {
    cache.Remove(breakKey);
    }
    }
    }
    else
    {
    expireHour = breakResumeFileExpireHour;
    int.TryParse(expireHour, out fileExpireHour);
    if (fileExpireHour == 0)
    {
    fileExpireHour = 24;
    }
    //fileCodeKey = (ConstVal.breakResumeFilePre + businessType + ":" + fileMd5Name).ToUpper();
    fileCodeKey = (ConstVal.breakResumeFilePre + fileMd5Name).ToUpper();
    fileOperatorService.AddToCache(fileCodeKey, ftpFile, fileExpireHour);
    LogHelper.GetLog(this).DebugFormat("断点续传内容MD5写入缓存:filename:'{0}', fileContentMD5:'{1}'", oldFileName, fileMd5Name);
    fileOperatorService.SetSuccessResponse(response, fileUploadResult, FileOperatorStatusCode.SaveSuccess);
    response.code = 0;
    response.error = string.Empty;
    }
    #endregion
    }
    else
    {
    var filePath = FtpOperationUtil.GetFileDefaultPath(((BusinessFileType)businessType).ToString());
    // 判断缓存
    //var fileCodeKey = (ConstVal.foreverFilePre + businessType + ":" + fileMd5Name).ToUpper();
    var fileCodeKey = (ConstVal.foreverFilePre + fileMd5Name).ToUpper();
    FtpFile ftpFile = new FtpFile();
    using (var cache = new StackExchangeRedis())
    {
    ftpFile = cache.Get<FtpFile>(fileCodeKey);
    }
    if (businessType == (int)BusinessFileType.ChatFile && ExchangeFilePath(ftpFile.filePath) != ExchangeFilePath(filePath))
    {
    FtpOperationUtil.MoveFile(ExchangeFilePath(oldFilePath + "/" + fileMd5Name), filePath);
    //// 更新文件信息
    //fileOperatorService.UpdateChatFile(businessType, fileMd5Name, filePath);
    ftpFile.filePath = filePath;
    fileOperatorService.AddToCache(fileCodeKey, ftpFile);
    }
    }
    }
    #endregion
    }
    }
    catch (Exception e)
    {
    response.code = -200;
    response.error = e.Message.ToString();
    LogHelper.GetLog(this).Error("异步上传异常:" + e.Message.ToString() + e.StackTrace);
    }
    return response;
    });
    #endregion
    return Json(response);
    }

    /// <summary>
    /// 上传文件根据业务类型上传进行断点续传
    /// </summary>
    /// <returns></returns>
    [IgnoreRequestStreamLog]
    //[HttpPost, Route("ResumeUploadFile")]
    [HttpPost]
    public async Task<JsonResult<BreakUploadResponse>> ResumeUploadFile()
    {
    // Check whether the POST operation is MultiPart?
    if (!Request.Content.IsMimeMultipartContent("form-data"))
    {
    throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
    }
    var response = new BreakUploadResponse
    {
    breakUploadResult = new List<BreakUploadResult>(),
    };
    #region 取流文件,然后决定是否保存文件至Ftp
    var provider = new MultipartFormDataMemoryStreamProvider();
    // Read the form and file data.
    BreakUploadResponse uploadResponse = await Request.Content.ReadAsMultipartAsync(provider)
    .ContinueWith<BreakUploadResponse>(o =>
    {
    try
    {
    #region 主文件信息
    if (!provider.FormData.AllKeys.Any(a => a.Equals("fileName", StringComparison.CurrentCultureIgnoreCase)) ||
    !provider.FormData.AllKeys.Any(a => a.Equals("blockCount", StringComparison.CurrentCultureIgnoreCase)) ||
    !provider.FormData.AllKeys.Any(a => a.Equals("totalSize", StringComparison.CurrentCultureIgnoreCase)))
    {
    response.code = -400;
    response.error = "请求参数错误,需包含主文件信息";
    return response;
    }
    else
    {
    response.fileName = provider.FormData.GetValues(provider.FormData.AllKeys.Where(w => w.Equals("fileName", StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault()).FirstOrDefault();
    response.fileCode = response.fileName;
    int blockCount = 0;
    var blockCountKey = provider.FormData.GetValues(provider.FormData.AllKeys.Where(w => w.Equals("blockCount", StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault()).FirstOrDefault();
    int.TryParse(blockCountKey, out blockCount);
    response.blockCount = blockCount;
    long totalSize;
    var totalSizeKey = provider.FormData.GetValues(provider.FormData.AllKeys.Where(w => w.Equals("totalSize", StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault()).FirstOrDefault();
    long.TryParse(totalSizeKey, out totalSize);
    response.totalSize = totalSize;
    if (blockCount == 0 || totalSize == 0L)
    {
    response.code = -400;
    response.error = "请求参数错误,主文件信息错误";
    return response;
    }
    }
    int businessType = 0;
    if (!provider.FormData.AllKeys.Any(a => a.Equals("businessType", StringComparison.CurrentCultureIgnoreCase)))
    {
    response.code = -(int)FileOperatorStatusCode.ParameterError;
    response.error = "请求参数错误,请求参数不包含业务类型信息!";
    return response;
    }
    else
    {
    var businessTypeKey = provider.FormData.GetValues(provider.FormData.AllKeys.Where(w => w.Equals("businessType", StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault()).FirstOrDefault();
    Int32.TryParse(businessTypeKey, out businessType);//从表单中获取到上传文件业务类型,输出赋值给busnissType
    var bustype = (BusinessFileType)businessType;
    var isSuccess = false;
    switch (bustype)
    {
    case BusinessFileType.HeadPortrait:
    case BusinessFileType.DynamicFile:
    case BusinessFileType.ChatFile:
    case BusinessFileType.AlbumFile:
    case BusinessFileType.LabelFile:
    case BusinessFileType.SpaceFile:
    case BusinessFileType.AdFile:
    isSuccess = true;
    break;
    default:
    isSuccess = false;
    break;
    }
    if (!isSuccess)
    {
    return new BreakUploadResponse
    {
    code = -(int)FileOperatorStatusCode.ParameterError,
    error = "请求参数错误,不支持的业务类型!"
    };
    }
    }
    #endregion

    foreach (MultipartFileData file in provider.FileData)
    {
    var breakUploadResult = new BreakUploadResult();
    #region 检查文件块信息
    foreach (var para in file.Headers.ContentDisposition.Parameters)
    {
    if (para.Name.ToLower().Equals("filename"))
    {
    breakUploadResult.fileName = para.Value.Trim('"');
    if (breakUploadResult.fileName.ToUpper() != response.fileName.ToUpper())//上传文件名称不等于请求文件名称,返回请求参数错误
    {
    response.code = -400;
    response.error = "请求参数错误,主文件信息与文件块信息不一致";
    return response;
    }
    continue;
    }
    if (para.Name.ToLower().Equals("blocknum"))
    {
    int blockNum;
    int.TryParse(para.Value.Trim('"'), out blockNum);
    breakUploadResult.blockNum = blockNum;
    continue;
    }
    if (para.Name.ToLower().Equals("blocksize"))
    {
    long blockSize;
    long.TryParse(para.Value.Trim('"'), out blockSize);
    breakUploadResult.blockSize = blockSize;
    continue;
    }
    }
    if (breakUploadResult.blockNum == 0 || breakUploadResult.blockSize == 0L)
    {
    response.code = -400;
    response.error = "请求参数错误,文件块信息错误";
    return response;
    }
    #endregion

    #region 检查扩展名黑白名单 文件主信息与明细信息
    var fileExt = response.fileName.Substring(response.fileName.LastIndexOf('.') + 1)?.ToLower();
    if (string.IsNullOrWhiteSpace(fileExt) || !FileExtensionUtil.IsWhiteContains(fileExt) || FileExtensionUtil.IsBlackContains(fileExt))
    {
    fileOperatorService.SetBlockErrorResponse(response, breakUploadResult, FileOperatorStatusCode.NotSupportType);
    continue;
    }
    #endregion

    using (var stream = ((MultipartFileDataStream)file).Stream)
    {
    #region 检查文件大小
    breakUploadResult.actualSize = stream.Length;
    // 最大文件大小
    if (breakUploadResult.actualSize <= 0)//如果当前上传文件大小小于0,返回请选择上传文件信息
    {
    fileOperatorService.SetBlockErrorResponse(response, breakUploadResult, FileOperatorStatusCode.NotExist);
    continue;
    }
    else if (breakUploadResult.actualSize > maxSizeUploadFile)//如果当前上传文件当前大小不等于上传文件最大大小,返回上传文件大小超过限制
    {
    fileOperatorService.SetBlockErrorResponse(response, breakUploadResult, FileOperatorStatusCode.OverSize);
    continue;
    }
    else if (breakUploadResult.actualSize != breakUploadResult.blockSize)//如果当前上传文件大小不等于请求文件块大小,返回数据文件不完整
    {
    fileOperatorService.SetBlockErrorResponse(response, breakUploadResult, FileOperatorStatusCode.NotFull);
    continue;
    }
    #endregion

    #region 根据文件名查询文件是否已存在 (需调用方把文件名改为文件内容MD5,再加后缀)
    var ftpFile = new FtpFile();
    FileBreakPoint fileBreakpoint = new FileBreakPoint
    {
    blocks = new List<FileBlockPoint>()
    };
    var fileContentMD5 = response.fileName.Substring(0, response.fileName.LastIndexOf('.')).ToUpper();
    var fileMd5Name = fileContentMD5 + "." + fileExt;
    //var fileMd5Key = (ConstVal.foreverFilePre + businessType + ":" + fileMd5Name).ToUpper();
    var fileMd5Key = (ConstVal.foreverFilePre + fileMd5Name).ToUpper();
    var fileBreakPointKey = (ConstVal.breakBlockFilePre + fileMd5Name).ToUpper();
    // 查询缓存
    using (var cache = new StackExchangeRedis())
    {
    ftpFile = cache.Get<FtpFile>(fileMd5Key);
    fileBreakpoint = cache.Get<FileBreakPoint>(fileBreakPointKey);
    } // 尽早释放using
    #region 数据库判断文件是否已经存在
    var oldFilePath = string.Empty;
    var fileMd5IsExist = fileOperatorService.CheckFileIsExist(fileMd5Name, businessType, out oldFilePath);
    #endregion
    if (fileMd5IsExist)
    {
    breakUploadResult = null;
    fileOperatorService.SetBlockSuccessResponse(response, breakUploadResult, FileOperatorStatusCode.AlreadyExists);
    LogHelper.GetLog(this).ErrorFormat("文件'{0}'已存在", response.fileName);
    response.isFinished = true;
    if (ftpFile != null)
    {
    // 聊天文件移动位置
    var filePath = FtpOperationUtil.GetFileDefaultPath(((BusinessFileType)businessType).ToString());
    if ((BusinessFileType)businessType == BusinessFileType.ChatFile && ExchangeFilePath(ftpFile.filePath) != ExchangeFilePath(filePath))
    {
    FtpOperationUtil.MoveFile(ExchangeFilePath(ftpFile.filePath), filePath);
    //var fileCodeKey = (ConstVal.foreverFilePre + businessType + ":" + fileMd5Name).ToUpper();
    var fileCodeKey = (ConstVal.foreverFilePre + fileMd5Name).ToUpper();
    ftpFile.filePath = filePath;
    fileOperatorService.AddToCache(fileCodeKey, ftpFile);
    }
    }
    return response;
    }
    else
    {
    if ((BusinessFileType)businessType != BusinessFileType.ChatFile)
    {
    var dbResult = fileOperatorService.GetFile(businessType, fileMd5Name);//获取文件信息
    if (dbResult != null && dbResult.Count > 0)//如果FTP服务器存在该文件,则返回文件已存在信息接口
    {
    breakUploadResult = null;
    fileOperatorService.SetBlockSuccessResponse(response, breakUploadResult, FileOperatorStatusCode.AlreadyExists);
    response.isFinished = true;
    return response;
    }
    }
    }
    if (fileBreakpoint == null)
    {
    fileBreakpoint = new FileBreakPoint
    {
    blocks = new List<FileBlockPoint>(),
    fileName = response.fileName,
    fileSize = response.totalSize,
    nodeName = ftpServerNodeName,
    filePath = FtpOperationUtil.rootPath + "/" + ((BusinessFileType)businessType).ToString() + "/" + dateTimePath,
    fileCode = fileMd5Name,
    blockCount = response.blockCount
    };
    var fileBlockPoint = new FileBlockPoint
    {
    fileName = breakUploadResult.fileName,
    blockNum = breakUploadResult.blockNum,
    blockSize = breakUploadResult.blockSize,
    isFinished = false
    };
    fileBreakpoint.blocks.Add(fileBlockPoint);
    // 加入缓存
    fileOperatorService.AddToCache(fileBreakPointKey, fileBreakpoint);
    }
    else
    {
    // 当前块已经上传完成,返回上传文件已存在
    if (fileBreakpoint.blocks.Any(w => w.blockNum == breakUploadResult.blockNum && w.isFinished == true))
    {
    fileOperatorService.SetBlockSuccessResponse(response, breakUploadResult, FileOperatorStatusCode.AlreadyExists);
    continue;
    }
    // 当前块未上传完成,把信息添加到断点续传
    if (!fileBreakpoint.blocks.Any(w => w.blockNum == breakUploadResult.blockNum))
    {
    var fileBlockPoint = new FileBlockPoint
    {
    fileName = breakUploadResult.fileName,
    blockNum = breakUploadResult.blockNum,
    blockSize = breakUploadResult.blockSize,
    isFinished = false
    };
    fileBreakpoint.blocks.Add(fileBlockPoint);
    }
    // 加入缓存
    fileOperatorService.AddToCache(fileBreakPointKey, fileBreakpoint);
    }
    #endregion

    #region Ftp操作
    #region 上传Ftp服务器
    // 获取完整存储路径(含 ftp:// 的绝对路径不含文件名)
    var fileBlockCompleteSize = FtpOperationUtil.UploadFileBlockOrBroken(stream, fileMd5Name + "." + breakUploadResult.blockNum, ExchangeFilePath(fileBreakpoint.filePath));//上传文件到FTP服务器(单次上传或续传)
    if (fileBlockCompleteSize == 0L)
    {
    fileOperatorService.SetBlockErrorResponse(response, breakUploadResult, FileOperatorStatusCode.SaveFileDefeated);//上传文件失败
    continue;
    }
    else
    {
    if (fileBlockCompleteSize == breakUploadResult.blockSize)//当上传文件大小等于上传文件块大小
    {
    var fileBlockPoint = new FileBlockPoint();
    fileBlockPoint = fileBreakpoint.blocks.Where(w => w.blockNum == breakUploadResult.blockNum).FirstOrDefault();
    fileBreakpoint.blocks.Remove(fileBlockPoint);
    fileBlockPoint.isFinished = true;
    fileBreakpoint.blocks.Add(fileBlockPoint);
    // 加入缓存
    fileOperatorService.AddToCache(fileBreakPointKey, fileBreakpoint);
    fileOperatorService.SetBlockSuccessResponse(response, breakUploadResult, FileOperatorStatusCode.SaveSuccess);//当前文件上传成功
    }
    else
    {
    fileOperatorService.SetBlockErrorResponse(response, breakUploadResult, FileOperatorStatusCode.SaveFileDefeated);
    continue;
    }
    }
    #endregion

    #region 全部上传完成则合并各个部分内容MD5缓存
    if (fileBreakpoint.blocks.All(w => w.isFinished == true) && (fileBreakpoint.blocks.Count == response.blockCount) && (fileBreakpoint.blocks.Sum(s => s.blockSize) == response.totalSize))
    {
    response.isFinished = true;
    // 合并文件
    List<string> fileFullPaths = fileBreakpoint.blocks.OrderBy(a => a.blockNum).Select(s => s.fileName + "." + s.blockNum).ToList();
    var remoteFilepath = ExchangeFilePath(fileBreakpoint.filePath);//转化文件路径
    // 文件合并后需返回 MD5是否一致TODO
    FtpOperationUtil.FileCombine(fileFullPaths, response.fileName, remoteFilepath, isCombineDelete ?? false);
    if ((BusinessFileType)businessType != BusinessFileType.ChatFile)
    {
    // 先写入数据库
    var dbResult = fileRepository.AddFile(response.fileName, businessType, fileMd5Name, ConfigUtil.GetConfigStr("FtpServerIP"), fileBreakpoint.filePath, 0);
    if (dbResult < 0)
    {
    fileOperatorService.SetBlockErrorResponse(response, breakUploadResult, FileOperatorStatusCode.DbSaveFileDefeated);
    return response;
    }
    }
    // 删除断点续传缓存
    using (var cache = new StackExchangeRedis())
    {
    cache.Remove(fileBreakPointKey);
    }
    // 加入内容缓存
    ftpFile = new FtpFile
    {
    fileName = response.fileName,
    nodeName = ftpServerNodeName,
    businessType = businessType, // 文件上传业务类型
    filePath = FtpOperationUtil.rootPath + "/" + ((BusinessFileType)businessType).ToString() + "/" + dateTimePath,
    fileCode = fileMd5Name
    };
    //var fileCodeKey = (ConstVal.foreverFilePre + businessType + ":" + fileMd5Name).ToUpper();
    var fileCodeKey = (ConstVal.foreverFilePre + fileMd5Name).ToUpper();
    //加入缓存
    fileOperatorService.AddToCache(fileCodeKey, ftpFile);
    LogHelper.GetLog(this).DebugFormat("写入内容MD5缓存:filename:'{0}', fileContentMD5:'{1}'", response.fileName + breakUploadResult.blockNum, fileMd5Name);
    response.code = 0;
    response.error = string.Empty;
    }
    #endregion
    #endregion
    }
    }
    }
    catch (Exception e)
    {
    response.code = -200;
    response.error = e.Message.ToString();
    LogHelper.GetLog(this).Error("异步上传异常:" + e.Message.ToString() + e.StackTrace);
    }
    return response;
    });
    #endregion
    return Json(response);
    }

    /// <summary>
    /// 图片上传压缩(流方式)
    /// </summary>
    /// <returns></returns>
    [IgnoreRequestStreamLog]
    //[HttpPost, Route("CompressImageUploadFile")]
    [HttpPost]
    public async Task<JsonResult<UploadImageResponse>> CompressImageUploadFile()
    {
    // Check whether the POST operation is MultiPart?
    if (!Request.Content.IsMimeMultipartContent("form-data"))
    {
    throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
    }
    var response = new UploadImageResponse
    {
    uploadResult = new List<UploadImageResult>(),
    // 文件保存失败
    code = (int)FileOperatorStatusCode.SaveFileDefeated,
    error = FileOperatorStatusCode.SaveFileDefeated.GetEnumText()
    };
    #region 取流文件,然后决定是否保存文件至Ftp
    var provider = new MultipartFormDataMemoryStreamProvider();
    // Read the form and file data.
    UploadImageResponse uploadResponse = await Request.Content.ReadAsMultipartAsync(provider)
    .ContinueWith(o =>
    {
    try
    {
    // This illustrates how to get the file names.
    foreach (MultipartFileData file in provider.FileData)
    {
    int businessType = 0;//上传文件业务类型
    if (!provider.FormData.AllKeys.Any(a => a.Equals("businessType", StringComparison.CurrentCultureIgnoreCase)))
    {
    response.code = -(int)FileOperatorStatusCode.ParameterError;
    response.error = "请求参数错误,请求参数不包含业务类型信息!";
    return response;
    }
    else
    {
    var businessTypeKey = provider.FormData.GetValues(provider.FormData.AllKeys.Where(w => w.Equals("businessType", StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault()).FirstOrDefault();
    Int32.TryParse(businessTypeKey, out businessType);//从表单中获取到上传文件业务类型,输出赋值给busnissType
    }
    var imageUploadResult = new UploadImageResult();
    imageUploadResult.compressFile = new List<PerFileInfo>();
    //接收文件
    var oldFileName = file.Headers.ContentDisposition.FileName.Trim('"');//获取上传文件实际的文件名
    var fileExt = oldFileName.Substring(oldFileName.LastIndexOf('.') + 1)?.ToLower();
    imageUploadResult.fileName = oldFileName;
    #region 检查扩展名黑白名单
    if (string.IsNullOrWhiteSpace(fileExt) || !FileExtensionUtil.IsImageNotCludeGif(fileExt))
    {
    fileOperatorService.SetErrorResponse(response, imageUploadResult, FileOperatorStatusCode.NotSupportType);
    continue;
    }
    #endregion
    using (var stream = ((MultipartFileDataStream)file).Stream)
    {
    #region 检查文件大小
    // 最大文件大小
    var fileLength = stream.Length;
    if (fileLength <= 0)
    {
    fileOperatorService.SetErrorResponse(response, imageUploadResult, FileOperatorStatusCode.NotExist);
    continue;
    }
    else if (fileLength > maxSizeUploadFile)
    {
    fileOperatorService.SetErrorResponse(response, imageUploadResult, FileOperatorStatusCode.OverSize);
    continue;
    }
    #endregion
    //大图片MD5
    var largeImageMD5 = FileMD5HashCodeUtil.GetFileContentMD5HashCode(stream);
    var beforeUploadImageInfos = fileOperatorService.CheckImageCompressEffect(stream);
    foreach (var uploadImageInfo in beforeUploadImageInfos)
    {
    var pressImage = new PerFileInfo();
    var imageMd5Name = uploadImageInfo.fileMd5Code + "." + fileExt;
    pressImage.imageCode = imageMd5Name;
    pressImage.imageSize = uploadImageInfo.fileSize;
    pressImage.imageHeight = uploadImageInfo.height;
    pressImage.imageWidth = uploadImageInfo.width;
    pressImage.imageSizeType = uploadImageInfo.imageSizeType;

    #region 根据文件内容MD5查询文件是否已存在
    var oldFilePath = string.Empty;
    var fileMd5IsExist = fileOperatorService.CheckFileIsExist(imageMd5Name, businessType, out oldFilePath);
    if (fileMd5IsExist)
    {
    fileMd5IsExist = true;
    imageUploadResult.compressFile.Add(pressImage);
    continue;
    }
    #endregion
    #region Ftp操作 上传Ftp
    if (!fileMd5IsExist)
    {
    #region 上传Ftp服务器
    // 获取完整存储路径(不含 ftp:// serverip)
    var filePath = fileOperatorService.SaveFileToFtp(uploadImageInfo.stream, imageMd5Name, FtpOperationUtil.GetFileDefaultPath(((BusinessFileType)businessType).ToString()));
    uploadImageInfo.stream.Position = 0;
    if (string.IsNullOrEmpty(filePath))
    {
    LogHelper.GetLog(this).Error("返回路径为空");
    pressImage.code = FileOperatorStatusCode.SaveFileDefeated;
    imageUploadResult.compressFile.Add(pressImage);
    continue;
    }
    #endregion
    #region 不存在则存入内容MD5缓存
    if ((BusinessFileType)businessType != BusinessFileType.ChatFile)
    {
    // 先写入数据库
    var dbResult = fileOperatorService.AddFile(businessType, oldFileName, imageMd5Name, filePath);
    if (!dbResult)
    {
    LogHelper.GetLog(this).Error("写入数据库失败");
    pressImage.code = FileOperatorStatusCode.DbSaveFileDefeated;
    imageUploadResult.compressFile.Add(pressImage);
    continue;
    }
    }
    imageUploadResult.compressFile.Add(pressImage);
    var ftpFile = new FtpFile();
    ftpFile = new FtpFile
    {
    fileName = oldFileName,
    businessType = businessType,
    nodeName = ftpServerNodeName,
    filePath = filePath,
    fileCode = imageMd5Name,
    fileType = fileExt
    };
    int fileExpireHour = 0;
    int.TryParse(ftpFileCacheExpireHour, out fileExpireHour);
    if (fileExpireHour == 0)
    {
    fileExpireHour = 24;
    }
    //var fileCodeKey = (ConstVal.foreverFilePre + businessType + ":" + imageMd5Name).ToUpper();
    var fileCodeKey = (ConstVal.foreverFilePre + imageMd5Name).ToUpper();
    using (var cache = new StackExchangeRedis())
    {
    // 文件内容MD5存入缓存
    cache.Set<FtpFile>(fileCodeKey, ftpFile, DateTime.Now.AddHours(fileExpireHour));
    }
    LogHelper.GetLog(this).DebugFormat("写入内容MD5缓存:filename:'{0}', fileContentMD5:'{1}'", oldFileName, imageMd5Name);
    #endregion
    }
    #endregion
    }
    if (imageUploadResult.compressFile != null && imageUploadResult.compressFile.All(a => a.isSuccess == true))
    {
    fileOperatorService.SetSuccessResponse(response, imageUploadResult, FileOperatorStatusCode.SaveSuccess);
    response.code = 0;
    response.error = string.Empty;
    }
    else
    {
    FileOperatorStatusCode errorCode = FileOperatorStatusCode.UnDefined;
    if (imageUploadResult.compressFile != null && imageUploadResult.compressFile.Any(a => a.isSuccess == false))
    {
    errorCode = imageUploadResult.compressFile.Where(a => a.isSuccess == false).FirstOrDefault().code;
    }
    fileOperatorService.SetErrorResponse(response, imageUploadResult, errorCode);
    }
    }
    }
    }
    catch (Exception e)
    {
    response.code = -200;
    response.error = e.Message.ToString();
    LogHelper.GetLog(this).Error("异步上传异常:" + e.Message.ToString() + e.StackTrace);
    }
    return response;
    });
    #endregion
    return Json(response);
    }
    #endregion

    #region 文件下载
    /// <summary>
    /// 文件下载
    /// </summary>
    /// <returns></returns>
    //[HttpGet, Route("DownloadFile/{fileCode}/{businessType}")]
    [IgnoreResponseStreamLog]
    [HttpGet]
    public async Task<HttpResponseMessage> DownloadFile(string fileCode, int? businessType = null)
    {
    fileCode = fileCode?.Replace("fileCode=", "");
    var taskResult = await Task.Run(async () =>
    {
    var response = Request.CreateResponse();
    try
    {
    if (string.IsNullOrWhiteSpace(fileCode))
    {
    return new HttpResponseMessage { StatusCode = HttpStatusCode.BadRequest, Content = new StringContent("{ "error":"请求参数不能为空" }", Encoding.GetEncoding("UTF-8"), "application/json") };
    }
    int fileMd5Len = 0;
    fileCode = FileExtensionUtil.FormatString(fileCode, out fileMd5Len);
    if (fileMd5Len != 32)
    {
    if (fileMd5Len == -1)
    {
    return new HttpResponseMessage { StatusCode = HttpStatusCode.BadRequest, Content = new StringContent("{ "error":"请求参数不含后缀名" }", Encoding.GetEncoding("UTF-8"), "application/json") };
    }
    return new HttpResponseMessage { StatusCode = HttpStatusCode.BadRequest, Content = new StringContent("{ "error":"请求参数不是MD5码" }", Encoding.GetEncoding("UTF-8"), "application/json") };
    }
    //var fileMd5Key = (ConstVal.foreverFilePre + businessType + ":" + fileCode).ToUpper();
    var fileMd5Key = (ConstVal.foreverFilePre + fileCode).ToUpper();
    var fileContentMD5 = fileCode.Substring(0, fileCode.LastIndexOf('.')).ToUpper();
    var fileExt = fileCode.Substring(fileCode.LastIndexOf('.') + 1);
    var fileMd5Name = fileContentMD5 + "." + fileExt;
    // Ftp上文件相对路径
    var remoteFilePath = string.Empty;
    #region 判断文件是否存在
    var fileMd5IsExist = fileOperatorService.CheckFileIsExist(fileMd5Name, businessType, out remoteFilePath);
    if (!fileMd5IsExist)
    {
    return new HttpResponseMessage { Content = new StringContent("{ "error":"文件不存在" }", Encoding.GetEncoding("UTF-8"), "application/json") };
    }
    #endregion
    #region Range 是否为断点续传
    long startPosition = -1;
    long endPosition = -1;
    var contentRange = string.Empty;
    long fileSize = 0;
    if (Request.Headers.Contains("Range"))
    {
    contentRange = Request.Headers.Range.Ranges.FirstOrDefault().ToString();
    //bytes 10000-19999/1157632
    if (!string.IsNullOrEmpty(contentRange))
    {
    contentRange = contentRange.Replace("bytes", "").Trim();
    contentRange = contentRange.Substring(0, contentRange.IndexOf("/") < 0 ? contentRange.Length : contentRange.IndexOf("/"));
    string[] ranges = contentRange.Split('-');
    long.TryParse(ranges[0], out startPosition);
    long.TryParse(ranges[1], out endPosition);
    fileSize = FtpOperationUtil.GetFileSize(ExchangeFilePath(remoteFilePath) + "/" + fileMd5Name);
    endPosition = endPosition == 0 ? fileSize : endPosition;
    if (startPosition >= endPosition)
    {
    startPosition = 0;
    endPosition = 0;
    LogHelper.GetLog().Info("下载节点大于等于结束节点");
    }
    if (endPosition >= fileSize)
    {
    startPosition = 0;
    endPosition = 0;
    LogHelper.GetLog().Info("结束节点大于总大小");
    }
    }
    }
    #endregion
    var mimeType = Extension2MimeType.ResourceManager.GetString(fileExt?.ToLower());
    if (string.IsNullOrWhiteSpace(mimeType))
    {
    mimeType = "application/octet-stream";
    }
    if (mimeType.StartsWith("video"))
    {
    #region Ftp下载
    var video = new VideoStream(remoteFilePath + "/" + fileMd5Name);
    Action<Stream, HttpContent, TransportContext> send = video.WriteToStream;
    response.Content = new PushStreamContent(send, new MediaTypeHeaderValue(mimeType));
    //response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
    response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("inline")
    {
    FileName = fileMd5Name
    };
    response.Headers.Add("Cache-Control", $"{cacheTime}");
    //调用异步数据推送接口
    return response;
    #endregion
    }
    else
    {
    #region Ftp下载
    Stream outputStream = new MemoryStream();
    if (outputStream == null || outputStream.Length == 0)
    {
    //if (startPosition >= 0 && endPosition != 0)
    if (endPosition > 0)
    {
    //outputStream = FtpOperationUtil.FtpBrokenDownload(ExchangeFilePath(remoteFilePath + "/" + fileMd5Name), true, startPosition, endPosition);
    outputStream = await FtpOperationUtil.FtpAsyncBrokenDownload(ExchangeFilePath(remoteFilePath + "/" + fileMd5Name), true, startPosition, endPosition);
    }
    else
    {
    //outputStream = FtpOperationUtil.FtpDownload(ExchangeFilePath(remoteFilePath + "/" + fileMd5Name));
    outputStream = await FtpOperationUtil.FtpAsyncDownload(ExchangeFilePath(remoteFilePath + "/" + fileMd5Name)) as MemoryStream;
    }
    }
    if (outputStream != null)
    {
    outputStream.Position = 0; // 重置下流读取位置
    response = new HttpResponseMessage(HttpStatusCode.OK)
    {
    Content = new StreamContent(outputStream)
    };
    response.Content.Headers.ContentType = new MediaTypeHeaderValue(mimeType);
    //response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
    response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("inline")
    {
    FileName = fileMd5Name
    };
    if (!string.IsNullOrEmpty(contentRange))
    {
    response.Content.Headers.Add("Content-Range", string.Format("bytes {0}-{1}/{2}", startPosition, endPosition, fileSize));
    }
    response.Headers.Add("Cache-Control", $"{cacheTime}");
    return response;
    }
    else
    {
    LogHelper.GetLog(this).DebugFormat("不存在文件名MD5:'{0}'", fileCode);
    return new HttpResponseMessage { Content = new StringContent("{ "error":"文件不存在"}", Encoding.GetEncoding("UTF-8"), "application/json") };
    }
    #endregion
    }
    }
    catch (Exception e)
    {
    LogHelper.GetLog(this).Error(e.Message.ToString() + e.StackTrace);
    return new HttpResponseMessage(HttpStatusCode.InternalServerError);
    }
    });
    return taskResult;
    }
    #endregion

    #region 检查是否存在
    /// <summary>
    /// 检查是否存在(返回文件大小、是否断点续传等信息)
    /// </summary>
    /// <param name="fileCode"></param>
    /// <param name="businessType"></param>
    /// <param name="isUpdateExpireTime"></param>
    /// <returns></returns>
    //[HttpGet, Route("IsFileExist/{fileCode}/{businessType}/{isUpdateExpireTime:bool=false}")]
    [HttpGet]
    public async Task<JsonResult<FileExistResponse>> IsFileExist(string fileCode)
    {
    int businessType = 3;
    bool isUpdateExpireTime = true;
    fileCode = fileCode?.Replace("fileCode=", "");
    FileExistResponse response = new FileExistResponse();
    response.blocks = new List<BlockPoint>();
    response.breakFile = new BreakFileInfo();
    if (string.IsNullOrWhiteSpace(fileCode))
    {
    response.error = "请求参数不能为空";
    return Json(response);
    }
    int fileMd5Len = 0;
    fileCode = FileExtensionUtil.FormatString(fileCode, out fileMd5Len);
    if (fileMd5Len != 32)
    {
    if (fileMd5Len == -1)
    {
    response.error = "请求参数不含后缀名";
    }
    else
    {
    response.error = "请求参数不是MD5码";
    }
    return Json(response);
    }
    var task = Task.Run(() =>
    {
    try
    {
    //var fileMd5Key = (ConstVal.foreverFilePre + businessType + ":" + fileCode).ToUpper();
    var fileMd5Key = (ConstVal.foreverFilePre + fileCode).ToUpper();
    var ftpFile = new FtpFile();
    var fileBreakPoint = new FileBreakPoint();
    // 判断缓存是否存在
    var fileContentMD5 = fileCode.Substring(0, fileCode.LastIndexOf('.')).ToUpper();
    var fileExt = fileCode.Substring(fileCode.LastIndexOf('.') + 1);
    var fileMd5Name = fileContentMD5 + "." + fileExt;
    var oldFilePath = string.Empty;
    var fileMd5IsExist = fileOperatorService.CheckFileIsExist(fileCode, businessType, out oldFilePath);
    if (!fileMd5IsExist)
    {
    var dbResponse = fileRepository.GetFile(0, string.Empty, fileCode);
    if (dbResponse.code == 0)
    {
    fileMd5IsExist = true;
    oldFilePath = dbResponse.filePath;
    }
    else
    {
    //var fileBreakResumeKey = (ConstVal.breakResumeFilePre + businessType + ":" + fileCode).ToUpper();
    var fileBreakResumeKey = (ConstVal.breakResumeFilePre + fileCode).ToUpper();
    using (ICachable cache = new StackExchangeRedis())
    {
    ftpFile = cache.Get<FtpFile>(fileBreakResumeKey);
    }
    if (ftpFile != null)
    {
    var breakResumeFileSize = FtpOperationUtil.GetFileSize(ExchangeFilePath(ftpFile.filePath) + "/" + fileMd5Name);
    response.isBreakResume = true;
    response.breakFile = new BreakFileInfo();
    response.fileCode = ftpFile.fileCode;
    response.breakFile.fileCode = ftpFile.fileCode;
    response.breakFile.fileSize = breakResumeFileSize;
    }
    else
    {
    // 是否分块续传
    var fileBreakPointKey = (ConstVal.breakBlockFilePre + fileCode).ToUpper();
    using (ICachable cache = new StackExchangeRedis())
    {
    fileBreakPoint = cache.Get<FileBreakPoint>(fileBreakPointKey);
    }
    if (fileBreakPoint != null)
    {
    response.isBreakPoint = true;
    response.fileCode = fileBreakPoint.fileCode;
    response.fileSize = fileBreakPoint.fileSize;
    //response.blocksFullSize = fileBreakPoint.fileSize;
    foreach (var block in fileBreakPoint.blocks)
    {
    // 查询看Ftp文件大小
    var blockFileSize = FtpOperationUtil.GetFileSize(ExchangeFilePath(fileBreakPoint.filePath) + "/" + fileBreakPoint.fileCode + "." + block.blockNum);
    var blockpoint = new BlockPoint
    {
    fileName = block.fileName,
    blockNum = block.blockNum,
    blockSize = block.blockSize,
    currentSize = blockFileSize,
    isFinished = block.isFinished
    };
    response.blocks.Add(blockpoint);
    }
    }
    }
    response.error = string.Format("'{0}'文件不存在", fileCode);
    LogHelper.GetLog(this).DebugFormat("'{0}'文件不存在", fileCode);
    return response;
    }
    }
    ftpFile = new FtpFile
    {
    businessType = businessType,
    nodeName = ftpServerNodeName,
    filePath = oldFilePath,
    fileCode = fileMd5Name
    };
    if (fileMd5IsExist && isUpdateExpireTime)
    {
    var filePath = FtpOperationUtil.GetFileDefaultPath(((BusinessFileType)businessType).ToString());
    if (oldFilePath.Contains(((BusinessFileType)businessType).ToString()) && ExchangeFilePath(oldFilePath) != ExchangeFilePath(filePath))
    {
    FtpOperationUtil.MoveFile(ExchangeFilePath(oldFilePath + "/" + fileMd5Name), filePath);
    ftpFile.filePath = filePath;
    fileOperatorService.AddToCache(fileMd5Key, ftpFile);
    }
    }
    // 获取Ftp文件大小
    var fileSize = FtpOperationUtil.GetFileSize(ExchangeFilePath(ftpFile.filePath) + "/" + ftpFile.fileCode);
    response.fileCode = ftpFile.fileCode;
    response.fileSize = fileSize;
    return response;
    }
    catch (Exception e)
    {
    response.error = "Api内部异常";
    LogHelper.GetLog(this).Error(e.Message.ToString() + e.StackTrace);
    return response;
    }
    });
    var taskResult = await Task.WhenAll(task);
    return Json(taskResult.FirstOrDefault());
    }
    #endregion

    #region Private Method
    /// <summary>
    /// 转化文件路径
    /// </summary>
    /// <param name="filePath"></param>
    /// <returns></returns>
    private string ExchangeFilePath(string filePath)
    {
    if (string.IsNullOrWhiteSpace(filePath))
    return filePath;
    var index = filePath.IndexOf(ftprootpath);
    if (index < 0)
    {
    if (filePath.Contains("ftp://"))
    {
    return filePath;
    }
    else
    {
    return Path.Combine(FtpOperationUtil.ftpURI, filePath);
    }
    }
    return Path.Combine(FtpOperationUtil.ftpURI, filePath.Substring(index));
    }
    #endregion Private Method
    }

    /// <summary>
    ///
    /// </summary>
    public class VideoStream
    {
    private readonly string _filefullname;
    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="fileFullName"></param>
    public VideoStream(string fileFullName)
    {
    _filefullname = fileFullName;
    }
    /// <summary>
    ///
    /// </summary>
    /// <param name="outputStream"></param>
    /// <param name="content"></param>
    /// <param name="context"></param>
    public async void WriteToStream(Stream outputStream, HttpContent content, TransportContext context)
    {
    try
    {
    var buffer = new byte[2048];
    var video = await FtpOperationUtil.FtpAsyncDownload(_filefullname);
    var bytesRead = buffer.Length;
    while (bytesRead == buffer.Length)
    {
    bytesRead = video.Read(buffer, 0, buffer.Length);
    await outputStream.WriteAsync(buffer, 0, bytesRead);
    }
    }
    catch (HttpException ex)
    {
    LogHelper.GetLog().Error(ex.Message + ex.StackTrace);
    }
    finally
    {
    outputStream.Close();
    }
    }
    /// <summary>
    /// 本地文件写入流
    /// </summary>
    /// <param name="outputStream"></param>
    /// <param name="content"></param>
    /// <param name="context"></param>
    public async void LocalFileWriteToStream(Stream outputStream, HttpContent content, TransportContext context)
    {
    try
    {
    var buffer = new byte[65536];
    using (var video = File.Open(_filefullname, FileMode.Open, FileAccess.Read))
    {
    var length = (int)video.Length;
    var bytesRead = 1;
    while (length > 0 && bytesRead > 0)
    {
    bytesRead = video.Read(buffer, 0, Math.Min(length, buffer.Length));
    await outputStream.WriteAsync(buffer, 0, bytesRead);
    length -= bytesRead;
    }
    }
    }
    catch (HttpException ex)
    {
    LogHelper.GetLog().Error(ex.Message + ex.StackTrace);
    }
    finally
    {
    outputStream.Close();
    }
    }

    }
    }

  • 相关阅读:
    word break II
    leetcode新题
    tensorflow数据读取过程
    python文本编辑: re.sub-------读取文本,去除指定字符并保存
    Anaconda安装及虚拟环境搭建教程(linux)
    语音合成
    关于Python错误提示: 'str' object is not callable
    语音识别学习阶段性总结(一)
    kaldi学习
    kaldi学习
  • 原文地址:https://www.cnblogs.com/Nine4Cool/p/10540619.html
Copyright © 2020-2023  润新知