zip 流方式demo
continuous-integration/drone/push Build is failing Details

Test_IRC_Net8^2
hang 2026-06-04 13:08:37 +08:00
parent 73fa62e6a2
commit d719015fa2
2 changed files with 62 additions and 49 deletions

View File

@ -1,4 +1,5 @@
using Aliyun.OSS; using Aliyun.OSS;
using CommunityToolkit.HighPerformance;
using DocumentFormat.OpenXml.EMMA; using DocumentFormat.OpenXml.EMMA;
using DocumentFormat.OpenXml.Office.CustomUI; using DocumentFormat.OpenXml.Office.CustomUI;
using DocumentFormat.OpenXml.Office2010.Excel; using DocumentFormat.OpenXml.Office2010.Excel;
@ -148,11 +149,9 @@ namespace IRaCIS.Core.Application.Service
private async Task CreateVisitZipAsync(string zipPath, List<ZipItem> zipItems) private async Task CreateVisitZipAsync(string zipPath, List<ZipItem> zipItems)
{ {
Directory.CreateDirectory( Directory.CreateDirectory(Path.GetDirectoryName(zipPath)!);
Path.GetDirectoryName(zipPath)!);
await using var zipFileStream = await using var zipFileStream = new FileStream(zipPath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4 * 1024 * 1024, useAsync: true);
new FileStream(zipPath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4 * 1024 * 1024, useAsync: true);
using var archive = new ZipArchive(zipFileStream, ZipArchiveMode.Create, leaveOpen: false); using var archive = new ZipArchive(zipFileStream, ZipArchiveMode.Create, leaveOpen: false);
@ -177,7 +176,9 @@ namespace IRaCIS.Core.Application.Service
if (!success) if (!success)
{ {
Log.Logger.Warning($"合并多帧失败:{item.ZipEntryPath}"); Log.Logger.Warning($"合并多帧失败:{item.ZipEntryPath} ossPath: {item.OssPath}");
throw new Exception($"合并多帧失败-终止当前zip包{item.ZipEntryPath} ossPath: {item.OssPath}");
} }
} }
@ -235,8 +236,7 @@ namespace IRaCIS.Core.Application.Service
var downloadVisits = MiniExcel.Query<SubjectVisitExcel>(Path.Combine(rootFolder, "download.xlsx")).ToList().Where(t => t.SubjectCode.IsNotNullOrEmpty() && t.VisitName.IsNotNullOrEmpty()).ToList(); var downloadVisits = MiniExcel.Query<SubjectVisitExcel>(Path.Combine(rootFolder, "download.xlsx")).ToList().Where(t => t.SubjectCode.IsNotNullOrEmpty() && t.VisitName.IsNotNullOrEmpty()).ToList();
downloadVisits = downloadVisits.Where(t => !oldVisits.Any(old => old.VisitNum == t.VisitNum && old.SubjectCode == t.SubjectCode && downloadVisits = downloadVisits.Where(t => !oldVisits.Any(old => old.VisitNum == t.VisitNum && old.SubjectCode == t.SubjectCode && old.VisitName.Trim().ToLower() == t.VisitName.Trim().ToLower())).ToList();
old.VisitName.Trim().ToLower() == t.VisitName.Trim().ToLower())).ToList();
var visitIndex = 0; var visitIndex = 0;
var skipCount = 0; var skipCount = 0;
@ -298,7 +298,7 @@ namespace IRaCIS.Core.Application.Service
if (downloadInfo == null) if (downloadInfo == null)
{ {
return ResponseOutput.Ok(); continue;
} }
#region 排除已经下载的 #region 排除已经下载的
@ -312,8 +312,7 @@ namespace IRaCIS.Core.Application.Service
StreamReaderFunc = (stream) => new StreamReader(stream, Encoding.GetEncoding("gb2312")) StreamReaderFunc = (stream) => new StreamReader(stream, Encoding.GetEncoding("gb2312"))
}).ToList(); }).ToList();
if (existVisits.Any(old => old.VisitNum == downloadVisit.VisitNum && old.SubjectCode == downloadVisit.SubjectCode && if (existVisits.Any(old => old.VisitNum == downloadVisit.VisitNum && old.SubjectCode == downloadVisit.SubjectCode && old.VisitName.Trim().ToLower() == downloadVisit.VisitName.Trim().ToLower()))
old.VisitName.Trim().ToLower() == downloadVisit.VisitName.Trim().ToLower()))
{ {
Log.Logger.Warning($"[{visitIndex}] Excel显示已下载跳过当前访视{downloadVisit.SubjectCode} {downloadVisit.VisitName} {downloadVisit.VisitNum}"); Log.Logger.Warning($"[{visitIndex}] Excel显示已下载跳过当前访视{downloadVisit.SubjectCode} {downloadVisit.VisitName} {downloadVisit.VisitNum}");
skipCount++; skipCount++;
@ -342,6 +341,8 @@ namespace IRaCIS.Core.Application.Service
var visitFolderName = $"{visitItem.SubjectCode}_{visitItem.VisitName.Trim()}"; var visitFolderName = $"{visitItem.SubjectCode}_{visitItem.VisitName.Trim()}";
#region DICOM
foreach (var studyInfo in visitItem.StudyList) foreach (var studyInfo in visitItem.StudyList)
{ {
var dirDic = new Dictionary<string, string>(); var dirDic = new Dictionary<string, string>();
@ -394,6 +395,11 @@ namespace IRaCIS.Core.Application.Service
foreach (var group in list.GroupBy(t => new { t.StudyInstanceUid, t.DicomStudyId })) foreach (var group in list.GroupBy(t => new { t.StudyInstanceUid, t.DicomStudyId }))
{ {
using var ms = new MemoryStream();
await DicomDIRHelper.GenerateStudyDIR(group.ToList(), dirDic, outputStream: ms);
var dicomDirBytes = ms.ToArray();
zipItems.Add(new ZipItem zipItems.Add(new ZipItem
{ {
@ -401,7 +407,7 @@ namespace IRaCIS.Core.Application.Service
CustomWriter = async entryStream => CustomWriter = async entryStream =>
{ {
await DicomDIRHelper.GenerateStudyDIR(group.ToList(), dirDic, outputStream: entryStream); await entryStream.WriteAsync(dicomDirBytes);
} }
}); });
} }
@ -412,7 +418,7 @@ namespace IRaCIS.Core.Application.Service
#endregion #endregion
#region DICOM
foreach (var seriesInfo in studyInfo.SeriesList) foreach (var seriesInfo in studyInfo.SeriesList)
{ {
@ -429,11 +435,13 @@ namespace IRaCIS.Core.Application.Service
} }
} }
#endregion
} }
#endregion
#region NoneDicom #region NoneDicom
foreach (var study in visitItem.NoneDicomStudyList) foreach (var study in visitItem.NoneDicomStudyList)
@ -453,15 +461,40 @@ namespace IRaCIS.Core.Application.Service
#endregion #endregion
var zipPath = Path.Combine(rootFolder, visitFolderName + ".zip");
Log.Logger.Warning($"开始压缩访视:{visitFolderName}"); #region zip
await CreateVisitZipAsync(zipPath, zipItems);
DownloadLogger.Write(logFilePath, visitItem.SubjectCode, visitItem.VisitNum, visitItem.VisitName, "Success"); var zipPath = Path.Combine(trialFolderPath, visitFolderName + ".zip");
Log.Logger.Warning($"[{visitIndex}] {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}开始打包下载访视:{visitFolderName}");
try
{
await CreateVisitZipAsync(zipPath, zipItems);
//Log.Logger.Warning($"zip exists={File.Exists(zipPath)} size={new FileInfo(zipPath).Length}");
Log.Logger.Warning($"[{visitIndex}] {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}访视打包下载完成:{visitFolderName}");
DownloadLogger.Write(logFilePath, visitItem.SubjectCode, visitItem.VisitNum, visitItem.VisitName, "Success");
}
catch (Exception ex)
{
Log.Logger.Warning($"出现异常{ex}删除压缩包:{visitFolderName}");
//如果有异常,删除失败的压缩包
if (File.Exists(zipPath))
{
File.Delete(zipPath);
}
}
#endregion
Log.Logger.Warning($"访视压缩完成:{visitFolderName}");
#endregion #endregion
@ -486,8 +519,6 @@ namespace IRaCIS.Core.Application.Service
public static class DownloadLogger public static class DownloadLogger
{ {
public static void Write( public static void Write(
string logFilePath, string logFilePath,
string subjectCode, string subjectCode,
@ -495,27 +526,34 @@ namespace IRaCIS.Core.Application.Service
string visitName, string visitName,
string? message = null) string? message = null)
{ {
bool fileExists = File.Exists(logFilePath); bool fileExists = File.Exists(logFilePath);
// 一次性打开文件流
using var stream = new FileStream( using var stream = new FileStream(
logFilePath, logFilePath,
FileMode.Append, FileMode.Append,
FileAccess.Write, FileAccess.Write,
FileShare.ReadWrite); FileShare.ReadWrite);
using var writer = new StreamWriter(stream, Encoding.UTF8); // 首次创建时写入 BOM
if (!fileExists)
{
var bom = new UTF8Encoding(true).GetPreamble();
stream.Write(bom, 0, bom.Length);
}
using var writer = new StreamWriter(stream, new UTF8Encoding(false));
// 首次写入表头 // 写入表头
if (!fileExists) if (!fileExists)
{ {
writer.WriteLine("Time,SubjectCode,VisitNum,VisitName,Message"); writer.WriteLine("Time,SubjectCode,VisitNum,VisitName,Message");
} }
// 写入数据
string line = string.Join(",", string line = string.Join(",",
[ [
Escape(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")), Escape(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")),
subjectCode, subjectCode,
visitNum, visitNum,
visitName, visitName,
@ -525,14 +563,12 @@ namespace IRaCIS.Core.Application.Service
writer.WriteLine(line); writer.WriteLine(line);
} }
// 防止逗号、换行导致 CSV 错乱
private static string Escape(string? value) private static string Escape(string? value)
{ {
if (string.IsNullOrEmpty(value)) if (string.IsNullOrEmpty(value))
return ""; return "";
value = value.Replace("\"", "\"\""); value = value.Replace("\"", "\"\"");
return $"\"{value}\""; return $"\"{value}\"";
} }
} }

View File

@ -1,30 +1,17 @@
using Aliyun.OSS; using Aliyun.OSS;
using DocumentFormat.OpenXml.Spreadsheet;
using FellowOakDicom; using FellowOakDicom;
using FellowOakDicom.Imaging; using FellowOakDicom.Imaging;
using IRaCIS.Application.Contracts; using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.BusinessFilter;
using IRaCIS.Core.Application.Contracts; using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Helper; using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.Helper.OtherTool;
using IRaCIS.Core.Application.Service.BusinessFilter;
using IRaCIS.Core.Application.ViewModel; using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Infra.EFCore.Context; using IRaCIS.Core.Infra.EFCore.Context;
using IRaCIS.Core.Infrastructure; using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Infrastructure.Encryption; using IRaCIS.Core.Infrastructure.Encryption;
using IRaCIS.Core.Infrastructure.NewtonsoftJson; using IRaCIS.Core.Infrastructure.NewtonsoftJson;
using MassTransit; using MassTransit;
using MassTransit.Caching.Internals;
using MassTransit.Mediator;
using MathNet.Numerics;
using MaxMind.GeoIP2;
using Medallion.Threading; using Medallion.Threading;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -32,25 +19,15 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using MiniExcelLibs; using MiniExcelLibs;
using Minio.DataModel;
using Newtonsoft.Json; using Newtonsoft.Json;
using NPOI.SS.Formula.Functions;
using NPOI.XWPF.UserModel; using NPOI.XWPF.UserModel;
using SharpCompress.Common;
using SixLabors.ImageSharp; using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing;
using System.Collections.Concurrent;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq.Dynamic.Core; using System.Linq.Dynamic.Core;
using System.Reactive.Subjects;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using static IRaCIS.Core.Domain.Share.StaticData;