net分片上传和下载

public class UploadFileService
{
    private readonly CacheService _cache;
    public UploadFileService(CacheService cache)
    {
        _cache = cache;
    }

    /// <summary>
    /// 分片上传文件
    /// </summary>
    /// <param name="file"></param>
    /// <param name="chunkNumber"></param>
    /// <param name="totalChunks"></param>
    /// <param name="fileName"></param>
    /// <param name="filePath"></param>
    /// <param name="fileHash"></param>
    /// <returns></returns>
    public async Task<FileBaseInfo?> UploadFile(IFormFile file, int chunkNumber, int totalChunks, string fileName, string filePath, string fileHash)
    {
        var tempPath = Path.Combine(filePath, $"{fileHash}.part{chunkNumber}");

        using (var stream = new FileStream(tempPath, FileMode.Create, FileAccess.Write))
        {
            await file.CopyToAsync(stream);
        }
        var value = _cache.GetValue<bool[]>(fileHash);
        if (value is null)
        {
            value = new bool[totalChunks];
        }
        value[chunkNumber] = true;

        await _cache.SetValueAsync(fileHash, value, 60 * 60);

        if (value.All(x => x))
        {
            var fileBaseInfo = await MergeFileChunks(fileName, totalChunks, filePath, fileHash);
            await _cache.RemoveAsync(fileHash);
            return projectFile;
        }
        return null;
    }

    /// <summary>
    /// 合并文件
    /// </summary>
    /// <param name="fileName"></param>
    /// <param name="totalChunks"></param>
    /// <param name="filePath"></param>
    /// <param name="fileHash"></param>
    /// <returns></returns>
    private async Task<FileBaseInfo> MergeFileChunks(string fileName, int totalChunks, string filePath, string fileHash)
    {
        var uploadPath = Path.Combine(filePath, fileName);
        
        //文件大小统计
        var size = 0L;
        using (var destinationStream = new FileStream(uploadPath, FileMode.Create, FileAccess.Write))
        {
            for (int i = 0; i < totalChunks; i++)
            {
                var tempPath = Path.Combine(filePath, $"{fileHash}.part{i}");

                using (var sourceStream = new FileStream(tempPath, FileMode.Open, FileAccess.Read))
                {
                    await sourceStream.CopyToAsync(destinationStream);
                }

                System.IO.File.Delete(tempPath);
            }
            size = destinationStream.Length;
        }
        var fileBaseInfo = new FileBaseInfo()
        {
            FileFormat = fileName.Substring(fileName.LastIndexOf(".") + 1),
            FileName = fileName,
            FilePath = uploadPath,
            Size = size,
        };
        return fileBaseInfo;
    }
}
/// <summary>
/// 分片上传文件
/// </summary>
/// <param name="folderId"></param>
/// <param name="file"></param>
/// <param name="chunkNumber"></param>
/// <param name="totalChunks"></param>
/// <param name="fileName"></param>
/// <param name="fileHash"></param>
/// <returns></returns>
[HttpPost("[action]/{folderId}")]
public async Task<ActionResult> UploadFile([FromRoute] Guid folderId, IFormFile file, [FromForm] int chunkNumber, [FromForm] int totalChunks, [FromForm] string fileName, [FromForm] string fileHash)
{
    if (file == null || chunkNumber < 0 || totalChunks <= 0 || string.IsNullOrEmpty(fileName))
    {
        return BadRequest("无效的请求参数。");
    }

    var folder = await _manager.FindAsync(folderId);
    if (folder is null)
    {
        return NotFound("不存在文件夹");
    }

    var fileBaseInfo = await _uploadFileService.UploadFile(file, chunkNumber, totalChunks, fileName, folder.FolderPath, fileHash);
    if (fileBaseInfo is not null)
    {
        fileBaseInfo.FolderId = folderId;
        await _manager.CommandContext.AddAsync(fileBaseInfo);
        await _manager.SaveChangesAsync();
    }
    return Ok();
}

/// <summary>
/// 查询分片上传到第几片
/// </summary>
/// <param name="fileHash"></param>
/// <returns></returns>
[HttpGet("upload/status")]
public ActionResult GetUploadStatus(string fileHash)
{
    if (string.IsNullOrEmpty(fileHash))
    {
        return BadRequest("文件名不能为空");
    }

    var chunks = _cache.GetValue<bool[]>(fileHash);

    if (chunks is not null)
    {
        return Ok(chunks.Select((uploaded, index) => new { ChunkNumber = index, Uploaded = uploaded }));
    }

    return Ok(null);
}
    /// <summary>
    /// 下载分析输入文件夹
    /// </summary>
    /// <param name="projectId"></param>
    /// <param name="folderId"></param>
    /// <returns></returns>
    [HttpGet("DownAnalysisInputDir/{projectId}/{folderId}")]
    public async Task<ActionResult> DownAnalysisInput([FromRoute] Guid projectId, [FromRoute] Guid folderId)
    {
        Response.Headers.ContentType = "application/zip";
        await _manager.DownAnalysisInputDir(Response.BodyWriter.AsStream(), projectId, folderId);
        await Response.CompleteAsync();
        return Ok();
    }
/// <summary>
/// 下载分析输入文件夹
/// </summary>
/// <param name="stream"></param>
/// <param name="projectId"></param>
/// <param name="folderId"></param>
/// <returns></returns>
public async Task DownAnalysisInputDir(Stream stream, Guid projectId, Guid folderId)
{
    using var zipArchive = new ZipArchive(stream, ZipArchiveMode.Create, true);
    var model = await GetAnalysisInputFolder(projectId, folderId);
    await AddFilesAndFoldersToZipAsync(zipArchive, projectId, model, "");
}

/// <summary>
/// 递归目录添加到zip中
/// </summary>
/// <param name="archive"></param>
/// <param name="projectId"></param>
/// <param name="container"></param>
/// <param name="entryPrefix"></param>
/// <returns></returns>
private async Task AddFilesAndFoldersToZipAsync(ZipArchive archive, Guid projectId, AnalysisInputFolderDto container, string entryPrefix)
{
    foreach (var folder in container.Folders)
    {
        var folderEntryPrefix = entryPrefix + folder.Name + "/";
        var folderEntry = archive.CreateEntry(folderEntryPrefix);
        var model = await GetAnalysisInputFolder(projectId, folder.Id);
        await AddFilesAndFoldersToZipAsync(archive, projectId, model, folderEntryPrefix);
    }

    foreach (var file in container.Files)
    {
        using var fileStream = System.IO.File.Open(file.FilePath, FileMode.Open, FileAccess.Read);
        using var entryStream = archive.CreateEntry(entryPrefix + file.FileName).Open();
        await fileStream.CopyToAsync(entryStream);
    }
}

 

posted @ 2024-08-22 09:44  一千零一夜  阅读(1)  评论(0编辑  收藏  举报