我无法弄清楚我在哪里错误地释放了资源/关闭了文件。我在任何地方都使用 using,但仍然出现该文件已被另一个进程使用的异常
public class DownloadControllerBase : ControllerBase
{
private readonly IUpdateFile _updateFile;
public DownloadControllerBase(IUpdateFile updateFile)
{
_updateFile = updateFile;
}
public async Task<IActionResult> DownloadFilesBase(
int userID,
string folderForDownloadCryptedFiles,
string zipFileName)
{
try
{
string encryptedFilesFolder = Path.Combine(folderForDownloadCryptedFiles, $"User({userID})");
string[] files = Directory.GetFiles(encryptedFilesFolder);
if (files.Length == 0)
return StatusCode(404, new { message = BaseErrorMessage.DownloadNoFiles });
string zipFilePath = Path.Combine(encryptedFilesFolder, zipFileName);
await CreateZipFile(userID, zipFilePath, files);
return await DeleteZipAndCreateResponse(zipFilePath, zipFileName);
}
catch (DirectoryNotFoundException)
{
return StatusCode(404, new { message = BaseErrorMessage.FolderNotFound });
}
}
private async Task CreateZipFile(int userID, string zipFilePath, string[] files)
{
using var zipStream = new FileStream(zipFilePath, FileMode.Create);
using var archive = new ZipArchive(zipStream, ZipArchiveMode.Create, true);
foreach (var file in files)
{
var fileInfo = new FileInfo(file);
var entry = archive.CreateEntry(fileInfo.Name, CompressionLevel.Fastest);
using (var entryStream = entry.Open())
using (var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read))
{
await fileStream.CopyToAsync(entryStream);
}
var fileName = Path.GetFileName(file);
await UpdateFile(userID, fileName);
await Task.Run(() => System.IO.File.Delete(file));
}
}
private async Task UpdateFile(int userID, string fileName)
{
var DbData = new UserFileModel()
{
user_id = userID,
file_name = fileName,
status = Status.downloaded.ToString(),
download_time = DateTime.UtcNow
};
await _updateFile.UpdateFileByNameOrID(DbData, "fileName");
}
private async Task<IActionResult> DeleteZipAndCreateResponse(string zipFilePath, string zipFileName)
{
using var stream = new FileStream(zipFilePath, FileMode.Open, FileAccess.Read);
await Task.Run(() => System.IO.File.Delete(zipFilePath));
return File(stream, "application/zip", zipFileName);
}
}
这是在控制器中调用该方法的方式:
[HttpGet("Download")]
public async Task<IActionResult> DownloadFiles([FromRoute] string type)
{
try
{
var param = _cryptographyParams.GetCryptographyParamsNoKey(type, FuncType.encrypt.ToString());
return await _downloadController.DownloadFilesBase(_userInfo.UserId, param.downloadFolder, "EncryptedFiles.zip");
}
catch (InvalidRouteException ex)
{
return StatusCode(404, new { message = ex.Message });
}
}
异常日志:
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.IO.IOException: The process cannot access the file 'C:\FileCryptWeb Users\Private\Encrypted files for download\User(22)\EncryptedFiles.zip' because it is being used by another process.
at Microsoft.Win32.SafeHandles.SafeFileHandle.CreateFile(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options)
at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
at System.IO.Strategies.FileStreamHelpers.ChooseStrategyCore(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access)
at FileCryptWeb.Controllers.BaseControllers.DownloadControllerBase.CreateZipFile(Int32 userID, String zipFilePath, String[] files) in C:\Users\Stewi\Source\Repos\air2921\FileCryptWeb\FileCryptWeb\Controllers\BaseControllers\DownloadControllerBase.cs:line 51
at FileCryptWeb.Controllers.BaseControllers.DownloadControllerBase.DownloadFilesBase(Int32 userID, String folderForDownloadCryptedFiles, String zipFileName) in C:\Users\Stewi\Source\Repos\air2921\FileCryptWeb\FileCryptWeb\Controllers\BaseControllers\DownloadControllerBase.cs:line 31
at FileCryptWeb.Controllers.CryptionControllers.EncryptionController.DownloadFiles(String type) in C:\Users\Stewi\Source\Repos\air2921\FileCryptWeb\FileCryptWeb\Controllers\EnryptionControllers\EncryptionController.cs:line 94
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at FileCryptWeb.JwtTokenMiddleware.Invoke(HttpContext context, FileCryptDbContext dbContext, ITokenService tokenService) in C:\Users\Stewi\Source\Repos\air2921\FileCryptWeb\FileCryptWeb\JwtTokenMiddleware.cs:line 47
at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
正如我在评论中已经写的那样,问题是您正在尝试删除打开用于流式传输的文件。
我在英语SO上找到了答案。您可以设置该标志
FileOptions.DeleteOnClose,以便正在流式传输的文件在使用后自动删除。其余参数只需简单编写,以便使用此参数调用所需的方法,并且必须在那里指定其余参数。