Excel等格式文件从服务端调用导出

服务端实现

Excel文件

/// <summary>
/// Excel文件
/// </summary>
/// <param name="requestDto">请求参数</param>
/// <returns></returns>
[HttpPost("[action]")]
public async Task<FileResult> XXXExcelStream([FromBody] XXXQueryRequestDto requestDto)
{
    byte[] bytes = await new XXXService(this).GetXXXExcelInfo(requestDto);
    if (bytes == null)
    {
        return null;
    }
    return File(bytes, "application/octet-stream", $"XXX数据{System.DateTime.Now:yyyyMMddHHmmss}.xlsx");
}

/// <summary>
/// Excel数组
/// </summary>
/// <param name="requestDto">请求参数</param>
/// <returns></returns>
[HttpPost("[action]")]
public async Task<ActionResult<byte[]>> XXXExcelInfo([FromBody] XXXQueryRequestDto requestDto)
{
    byte[] bytes = await new XXXService(this).GetXXXExcelInfo(requestDto);
    return bytes;
}

通用实现

ASP.NET Core中,可返回File对象。
动态获取文件类型,客户端可使用MimeMapping.GetMimeMapping,或有权限时通过注册表Registry.ClassesRoot获取,具体实现网上可查。
ASP.NET Core没有具体接口,可手动实现。Http Content-Type对照表

public FileResult GetFile(string url)
{
    var fileEntity = new FileHelper(url);
    if (string.IsNullOrEmpty(fileEntity.FileInfo.FileName))
    {
        return null;
    }
    string fileName = fileEntity.FileInfo.FileName;
    string extension = Path.GetExtension(fileName).ToLower();
    string contentType = FileContentTypeHelper.GetMimeType(extension);
    string fileDownloadName = $"{DateTime.Now:yyyyMMddHHmmss}{extension}";
    return File(fileName, contentType, fileDownloadName);
}

FileHelper

通用实现2

[HttpGet]
public IActionResult Download(string key)
{
    var decodeKey = WebUtility.UrlDecode(key);
    string fileName = decodeKey.Substring(decodeKey.LastIndexOf('/') + 1);
    if (string.IsNullOrEmpty(fileName))
    {
        throw new NotImplementedException("fileName is NULL!");
    }
    try
    {
        _logger.LogInformation("Download: " + decodeKey);
        var stopwatch = new Stopwatch();
        stopwatch.Start();
        var stream = _fileAdapter.GetFile(decodeKey);
        stopwatch.Stop();
        _logger.LogInformation($"耗时: {stopwatch.ElapsedMilliseconds} ms");

        if (stream == null)
        {
            return Content("文件为空!!");
        }
        long len = _fileAdapter.FileLength(decodeKey);
        string extension = Path.GetExtension(fileName).ToLower();
        string contentType = FileContentTypeHelper.GetMimeType(extension);

        return DownloadFile(stream, fileName, len, contentType);
    }
    catch (Exception ex)
    {
        _logger.LogError(ex.Message);
    }
    return null;
}

其中,_fileAdapter可以是阿里云、华为云等云oss下载库的封装对象。FileContentTypeHelper是文件的Content-Type帮助类。

/// <summary>
/// 缓冲区中的文件流发给客户端
/// </summary>
/// <param name="stream">二进制文件流</param>
/// <param name="fileName">文件名称</param>
/// <param name="length">文件长度</param>
/// <param name="contentType">文件的内容类型</param>
/// <returns></returns>
protected IActionResult DownloadFile(Stream stream, string fileName, long length, string contentType = "application/octet-stream")
{
    Response.ContentType = contentType;
    Response.Headers.Add("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8));
    //Response.Headers.Add("Transfer-Encoding", "chunked");
    Response.Headers.Add("Content-Length", length.ToString());
    Response.Headers.Add("Access-Control-Allow-Origin", "*");
    Response.Headers.Add("Access-Control-Allow-Credentials", "true");

    int bufferSize = FileHelper.CACHESIZE;
    using (stream)
    {
        using (Response.Body)
        {
            long hasRead = 0;
            int curRead = 0;
            var buffer = new byte[bufferSize];
            while ((curRead = stream.Read(buffer, 0, bufferSize)) != 0) // 读取内容到服务器内存中
            {
                if (HttpContext.RequestAborted.IsCancellationRequested)
                {
                    // 如果客户端中断了服务器的连接,取消下载文件的读取和发送
                    break;
                }
                Response.Body.Write(buffer, 0, curRead);
                Response.Body.Flush();  // 释放服务器内存空间
                hasRead += curRead;     // 更新已经发送到客户端浏览器的字节数
                //Console.WriteLine($"{DateTime.Now} {fileName} 数据流分段写 {length}/{hasRead}");
            }
        }
    }

    return new EmptyResult();
}

客户端调用

Excel文件

private async Task BtnExportClickAsnc(XXXRequestDto dto, string fileName)
{
    var response = XXXAPI.XXXExcelStreamWithHttpMessagesAsync(dto);
    Stream stream = await response.Response.Content.ReadAsStreamAsync();
    if (stream != null)
    {
        using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
        {
            await stream.CopyToAsync(fs);
            fs.Flush();
        }
    }
}

private async Task BtnExportClickAsnc(XXXRequestDto dto, string fileName)
{
    var response = XXXAPI.XXXExcelInfoWithHttpMessagesAsync(dto);
    try
    {
        byte[] data = response.Body;
        File.WriteAllBytes(fileName, data);
    }
    catch (Exception ex)
    {
    }
}
原文地址:https://www.cnblogs.com/wesson2019-blog/p/13564058.html