.net8导出影像图片按现场及天拆分

发布于:2025-07-02 ⋅ 阅读:(23) ⋅ 点赞:(0)

需求说明

根据日期查询出这个时间段内的现场图片,然后选择现场导出。导出的图片按照一个现场一个文件夹,并且每个现场下按天拆分文件夹。需要兼容文件存储和文件存储的方式。

关键效果图

在这里插入图片描述
在这里插入图片描述

上传Controller关键部分

Controller部分


public class UploadController{
	private readonly IWebHostEnvironment _env;
	readonly FileService _fileservice;
	 public UploadController(
	 FileService fileservice,
     IWebHostEnvironment env)
	 {
	 	 _fileservice = fileservice;
	     _env = env;
	 }
	/// <summary>
	/// 现场图片下载
	/// </summary>
	/// <returns></returns>
	[HttpPost]
	public async Task<Result> SceneImageDownload(JObject obj)
	{
	    var exportData = obj.GetObject<ScenePhoto_Export>("exportData");
	    return await _fileservice.SceneImageDownload(exportData, _env.ContentRootPath);
	}
}

Servcie部分

public async Task<Result> SceneImageDownload(ScenePhoto_Export exportData, string outputPath = "")
{
    switch (StorageConfig)
    {
        case StorageConfig.Cos:  //cos存储
        case StorageConfig.Oss:  //oss存储
        case StorageConfig.Obs:  //obs存储
                                  当前年月日字符串
            var tziprelativePath = $"ExportFiles/{DateTime.Now.Year}/{DateTime.Now.Month}/{DateTime.Now.Day}/"; //相对路径
            string tzipOutputRoot = Path.Combine(outputPath, tziprelativePath.Replace("/", Path.DirectorySeparatorChar.ToString()));
            // 确保目录存在
            if (!Directory.Exists(tzipOutputRoot))
            {
                Directory.CreateDirectory(tzipOutputRoot);
            }
            string texportFolderName = $"{exportData.Title}";
            string ttempExportPath = Path.Combine(Path.GetTempPath(), texportFolderName);
            Directory.CreateDirectory(ttempExportPath);
            var failList = new List<string>();
            System.Net.WebClient mywebclient = new System.Net.WebClient();
            try
            {
                foreach (var scene in exportData.SceneList)
                {
                    string sceneFolder = Path.Combine(ttempExportPath, scene.Name);
                    Directory.CreateDirectory(sceneFolder);

                    foreach (var day in scene.DayList)
                    {
                        string dayFolder = Path.Combine(sceneFolder, day.ForDate.ToString("yyyy-MM-dd"));
                        Directory.CreateDirectory(dayFolder);

                        foreach (var picGuid in day.PicList)
                        {
                            // 查 PicRelation 获取远程文件信息
                            var picData = await _dbContext.Set<PicRelation>()
                                .Where(p => p.Pic == picGuid || p.Pic == new Guid(picGuid).ToString())
                                .Select(p => new
                                {
                                    p.RemoteUrl,
                                    p.Format,
                                })
                                .FirstOrDefaultAsync();

                            if (picData == null || string.IsNullOrEmpty(picData.RemoteUrl))
                            {
                                failList.Add($"未找到云存储图片或 RemoteUrl:{picGuid}");
                                continue;
                            }

                            // 处理文件名,没有 FileName 就用 picGuid + 后缀
                            string extension = string.IsNullOrWhiteSpace(picData.Format) ? ".jpg" : "." + picData.Format.Trim('.');
                            string fileName = picGuid + extension;

                            string destPath = Path.Combine(dayFolder, fileName);

                            try
                            {
                                var bytes = await mywebclient.DownloadDataTaskAsync(picData.RemoteUrl);
                                await System.IO.File.WriteAllBytesAsync(destPath, bytes);
                            }
                            catch (Exception ex)
                            {
                                failList.Add($"下载云存储图片失败:{picGuid},错误:{ex.Message}");
                            }
                        }
                    }
                }

                if (failList.Any())
                {
                    string failLogPath = Path.Combine(ttempExportPath, "导出失败.txt");
                    await System.IO.File.WriteAllLinesAsync(failLogPath, failList);
                }

                string zipFileName = $"{texportFolderName}.zip";
                string finalZipPath = Path.Combine(tzipOutputRoot, zipFileName);
                // 如果已存在,删除旧文件
                if (System.IO.File.Exists(finalZipPath))
                {
                    System.IO.File.Delete(finalZipPath);
                }
                ZipFile.CreateFromDirectory(ttempExportPath, finalZipPath);

                var zipPath = $"{_configuration["Service_ApiUrl"]}/{tziprelativePath}{texportFolderName}.zip";
                return Result.NewSuccess(data: zipPath);
            }
            catch (Exception ex)
            {
                return Result.NewError(message: "导出失败");
            }
            finally
            {
                if (Directory.Exists(ttempExportPath))
                    Directory.Delete(ttempExportPath, true);
            }
            break;
        case StorageConfig.File: //文件存储
            var picGuids = exportData.SceneList.SelectMany(t => t.DayList.SelectMany(t => t.PicList)).Select(s => s).ToList();
            var tpicGuids = picGuids.Select(t => new Guid(t).ToString()).ToList();
            if (string.IsNullOrEmpty(AppStartingCache.FileStorage_BaseUrl))
            {
                bool.TryParse(_configuration["FileWebServer_Db:IsLocal"], out bool islocal);
                AppStartingCache.FileStorage_IsLocal = islocal;
                AppStartingCache.FileStorage_BaseUrl = $"http://{_configuration["FileWebServer_Db:ServerHost"]}:{_configuration["FileWebServer_Db:ServerPort"]}";
            }
            if (!AppStartingCache.FileStorage_IsLocal)  //远程获取
            {
                string fullurl = $"{AppStartingCache.FileStorage_BaseUrl}/file/msupload/SceneImageDownload?";
                var rst = await HttpClientProxy_Mis.Post2Async<Result<string>>($"{fullurl}", para: new
                {
                    exportData = exportData
                });
                return rst;
            }
            else
            {
                // 查询图片路径前缀(ServerUseFor = 0)
                string imageRoot = _dbContext.Set<ImageServerInfo>()
                    .Where(s => s.ServerUseFor == ServerUseFor.Pic)
                    .Select(s => s.PicRootPath)
                    .FirstOrDefault();

                // 查询压缩包输出根路径(ServerUseFor = 2)
                string zipOutputRoot = _dbContext.Set<ImageServerInfo>()
                    .Where(s => s.ServerUseFor == ServerUseFor.LargeFile)
                    .Select(s => s.PicRootPath)
                    .FirstOrDefault();
                var serverId = _dbContext.Set<ImageServerInfo>()
                    .Where(s => s.ServerUseFor == ServerUseFor.LargeFile)
                    .Select(s => s.Id)
                    .FirstOrDefault();
                if (string.IsNullOrEmpty(imageRoot) || string.IsNullOrEmpty(zipOutputRoot))
                {
                    return Result.NewError(message: "图片路径前缀或导出目录未配置。");
                }
                //得到所有图片的地址及名称
                var temp = await _dbContext.Set<ImageInfo>().Where(a => picGuids.Contains(a.PicGuid)).Select(s => new
                {
                    s.PicGuid,
                    s.PicName,
                    s.Format,
                    s.RelativePath
                }).ToListAsync();
                if (temp.Count == 0)
                {
                    temp = await _dbContext.Set<ImageInfo>().Where(a => tpicGuids.Contains(a.PicGuid)).Select(s => new
                    {
                        s.PicGuid,
                        s.PicName,
                        s.Format,
                        s.RelativePath
                    }).ToListAsync();
                }

                if (temp.Count > 0)//表示有图片 
                {
                    var imageInfoDict = temp.ToDictionary(x => x.PicGuid, x => x);
                    // 3. 临时目录(系统临时目录)
                    string exportFolderName = $"{exportData.Title}";
                    string tempExportPath = Path.Combine(Path.GetTempPath(), exportFolderName);
                    Directory.CreateDirectory(tempExportPath);
                    try
                    {
                        foreach (var scene in exportData.SceneList)
                        {
                            string sceneFolder = Path.Combine(tempExportPath, scene.Name);
                            Directory.CreateDirectory(sceneFolder);

                            foreach (var day in scene.DayList)
                            {
                                string dayStr = day.ForDate.ToString("yyyy-MM-dd");
                                string dayFolder = Path.Combine(sceneFolder, dayStr);
                                Directory.CreateDirectory(dayFolder);

                                foreach (var picGuid in day.PicList)
                                {
                                    if (!imageInfoDict.TryGetValue(picGuid, out var imageInfo))
                                        continue; // 没有查到图片信息,跳过

                                    string relativePath = imageInfo.RelativePath.Replace("/", Path.DirectorySeparatorChar.ToString());
                                    string extension = string.IsNullOrWhiteSpace(imageInfo.Format) ? ".jpg" : "." + imageInfo.Format.Trim('.');
                                    string sourcePath = Path.Combine(imageRoot, relativePath);
                                    string destPath = Path.Combine(dayFolder, imageInfo.PicName + extension);

                                    if (System.IO.File.Exists(sourcePath))
                                    {
                                        System.IO.File.Copy(sourcePath, destPath, true);
                                    }
                                    else
                                    {
                                        Console.WriteLine($"文件不存在:{sourcePath}");
                                    }
                                }
                            }
                        }
                        // 4. 生成 zip 文件到 ServerUseFor=1 路径下
                        string zipFileName = $"{exportData.Title}.zip";
                         当前年月日字符串
                        var ziprelativePath = $"ExportFiles/{DateTime.Now.Year}/{DateTime.Now.Month}/{DateTime.Now.Day}/"; //相对路径
                        // 构建完整导出路径
                        string finalFolderPath = Path.Combine(zipOutputRoot, ziprelativePath.Replace("/", Path.DirectorySeparatorChar.ToString()));
                        // 确保目录存在
                        if (!Directory.Exists(finalFolderPath))
                        {
                            Directory.CreateDirectory(finalFolderPath);
                        }
                        string finalZipPath = Path.Combine(finalFolderPath, zipFileName);
                        // 如果已存在,删除旧文件
                        if (System.IO.File.Exists(finalZipPath))
                        {
                            System.IO.File.Delete(finalZipPath);
                        }
                        ZipFile.CreateFromDirectory(tempExportPath, finalZipPath);
                        var guid = Guid.NewGuid().ToString("");
                        string zipextension = Path.GetExtension(zipFileName)?.TrimStart('.') ?? "";
                        await _dbContext.Set<ImageInfo>().AddAsync(new ImageInfo
                        {
                            PicName = zipFileName,
                            Format = zipextension,
                            RelativePath = ziprelativePath + exportData.Title + ".zip", // 存储图片相对路径
                            ImageServerId = serverId, // 存储服务器编号
                            PicGuid = guid,
                            CreateOnYMD = DateTime.Now.DateTimeYMD_Int()
                        });
                        await _dbContext.SaveChangesAsync();
                        var serverUrl = await _dbContext.Set<ImageServerInfo>().Where(a => a.Id == serverId).Select(a => a.ServerUrl).FirstOrDefaultAsync();
                        var zipPath = $"{serverUrl}file/msupload/file_misimage?id={guid}";
                        return Result.NewSuccess(data: zipPath);
                    }
                    catch (Exception ex)
                    {
                        return Result.NewError(message: "导出失败");
                    }
                    finally
                    {
                        // 清理临时文件夹
                        if (Directory.Exists(tempExportPath))
                            Directory.Delete(tempExportPath, true);
                    }
                }
                return Result.NewError(message: "暂无可导出图片");
            }
            break;
    }
    return Result.NewError(message: "导出失败");
}

文件存储controlelr关键部分

 [HttpGet]
 public async Task<FileResult> File_Misimage(string id)
 {
     var rst = await _fileservice.File_Misimage(id);
     if (!string.IsNullOrEmpty(rst.Format))
     {
         rst.Format = rst.Format.Contains('.') ? rst.Format.TrimStart('.') : rst.Format;
         return File(rst.Pic, MIMEHelper.GetMimeValue(rst.Format), fileDownloadName: $"{rst.FileName}.{rst.Format}");
     }
     else
     {
         var defaultPic = _defaultimg.DefaultFileStream();
         return File(defaultPic, MIMEHelper.GetMimeValue("png"), fileDownloadName: "default");
     }
 }

文件存储获取文件关键部分

 public async Task<PicByteData> File_Misimage(string id)
 {
     switch (StorageConfig)
     {
         case StorageConfig.Cos:
         case StorageConfig.Oss:
         case StorageConfig.Obs:
             var tempid = new Guid(id).ToString();
             var picData = await _dbContext.Set<PicRelation>().Where(a => a.Pic == tempid).Select(a => new { a.RemoteUrl, a.Format }).FirstOrDefaultAsync();
             if (picData == null)
             {
                 picData = await _dbContext.Set<PicRelation>().Where(a => a.Pic == id).Select(a => new { a.RemoteUrl, a.Format }).FirstOrDefaultAsync();
             }
             if (picData != null)
             {
                 byte[] Bytes = null;
                 using (WebClient mywebclient = new WebClient())
                 {
                     Bytes = mywebclient.DownloadData(picData.RemoteUrl);
                 }
                 return new PicByteData { Pic = Bytes, Format = picData.Format };
             }
             break;
         case StorageConfig.Sqlserver:
             var guid = new Guid(id);
             var tmp = await _dbContext.Set<PicStorage>().Where(a => a.Id == guid).Select(a => new { a.Pic, a.Format }).FirstOrDefaultAsync();
             if (tmp != null)
             {
                 return new PicByteData { Pic = tmp.Pic, Format = tmp.Format };
             }
             break;

         case StorageConfig.File:
             var tid = new Guid(id).ToString();
             if (string.IsNullOrEmpty(AppStartingCache.FileStorage_BaseUrl))
             {
                 bool.TryParse(_configuration["FileWebServer_Db:IsLocal"], out bool islocal);
                 AppStartingCache.FileStorage_IsLocal = islocal;
                 AppStartingCache.FileStorage_BaseUrl = $"http://{_configuration["FileWebServer_Db:ServerHost"]}:{_configuration["FileWebServer_Db:ServerPort"]}";
             }
             if (!AppStartingCache.FileStorage_IsLocal)  //远程获取
             {
                 string fullurl = $"{AppStartingCache.FileStorage_BaseUrl}/file/msupload/file_misimage_byte?id={tid}";
                 var ret = await HttpClientProxy_Mis.GetAsync<PicByteData>(fullurl);
                 return ret;
             }
             else
             {
                 var temp = await (from r in _dbContext.Set<ImageInfo>().Where(a => a.PicGuid == tid)
                                   join s in _dbContext.Set<ImageServerInfo>() on r.ImageServerId equals s.Id
                                   select new
                                   {
                                       s.PicRootPath,
                                       r.RelativePath,
                                       r.Format,
                                       r.PicName
                                   }).FirstOrDefaultAsync();
                 if (temp == null)
                 {
                     temp = await (from r in _dbContext.Set<ImageInfo>().Where(a => a.PicGuid == id)
                                   join s in _dbContext.Set<ImageServerInfo>() on r.ImageServerId equals s.Id
                                   select new
                                   {
                                       s.PicRootPath,
                                       r.RelativePath,
                                       r.Format,
                                       r.PicName
                                   }).FirstOrDefaultAsync();
                 }
                 if (temp != null)
                 {
                     var fullpath = temp.PicRootPath + temp.RelativePath;
                     byte[] bytes = null;
                     using (var picstream = System.IO.File.OpenRead(fullpath))
                     {
                         bytes = picstream.ConvertStreamToBytes();
                         picstream.Dispose();
                     }
                     return new PicByteData { Pic = bytes, Format = temp.Format, FileName = temp.PicName };
                 }
             }
             break;

         default:
             break;
     }
     return new PicByteData();
 }

模型部分

  public class PicByteData
  {
      public byte[] Pic { get; set; }
      public string Format { get; set; }
      /// <summary>
      /// 文件名称
      /// </summary>
      public string FileName { get; set; }
  }


网站公告

今日签到

点亮在社区的每一天
去签到