我目前正在应用程序中开发文件上传功能,但遇到上传的文件似乎已损坏的问题。该应用程序旨在处理分块上传的大文件,虽然它成功收集了所有大小匹配的块,但最终组装的文件似乎已损坏且无法打开。
我实现了一个内存流来处理文件块,并且在收到最终块后将组装的文件保存到磁盘。尽管如此,生成的文件仍然无法访问。我怀疑内存流的使用方式或对磁盘的最终写入操作可能存在问题。
我使用以下代码来管理文件块并保存组装的文件:
private readonly ConcurrentDictionary<string, MemoryStream> fileChunks = new ConcurrentDictionary<string, MemoryStream>();
[HttpPost("UploadFileChunk")]
public async Task<bool> UploadFileChunk([FromBody] FileChunkDto fileChunkDto)
{
try
{
// get the local filename
string filePath = Environment.CurrentDirectory + "\\StaticFiles\\";
string fileName = filePath + fileChunkDto.FileName;
// delete the file if necessary
//if (fileChunkDto.FirstChunk && System.IO.File.Exists(fileName))
// System.IO.File.Delete(fileName);
if (!fileChunks.TryGetValue(fileName, out MemoryStream? memoryStream))
{
memoryStream = new MemoryStream();
fileChunks.TryAdd(fileName, memoryStream);
}
memoryStream.Seek(fileChunkDto.Offset, SeekOrigin.Begin);
await memoryStream.WriteAsync(fileChunkDto.Data!, 0, fileChunkDto.Data!.Length);
if (fileChunkDto.LastChunk)
{
using (FileStream fileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
memoryStream.Seek(0, SeekOrigin.Begin);
await memoryStream.CopyToAsync(fileStream);
}
memoryStream.Dispose();
var extention = Path.GetExtension(fileChunkDto.FileName).ToLower();
var justFileName = Path.GetFileNameWithoutExtension(fileChunkDto.FileName);
var (fileName2, fileType) = GetFileNameFileType(fileChunkDto.To!, justFileName);
var to = fileChunkDto.To!.ToLower();
var clientsRequest = new ClientsRequest()
{
ClientId = fileChunkDto.ClientId,
RequestId = fileChunkDto.RequestId,
CreateDate = DateTime.UtcNow
};
await _context.ClientsRequests.AddAsync(clientsRequest);
await _context.SaveChangesAsync();
string filenameAfterConvertion = await UploadDocumentToS3(fileChunkDto, fileName, fileType);
if (filenameAfterConvertion != null)
{
return true;
}
return false;
}
return false;
}
catch (Exception ex)
{
var msg = ex.Message;
return false;
}
}
我怀疑我管理内存流和处理最终写入操作的方式可能存在问题,但我似乎无法弄清楚
我将非常感谢任何有关如何解决此问题并确保上传的文件不损坏的见解或建议。预先感谢您的帮助,如果需要更多信息,请在评论中告诉我。
bug已上线
memoryStream.Seek(fileChunkDto.Offset, SeekOrigin.Begin);
await memoryStream.WriteAsync(fileChunkDto.Data!, 0, fileChunkDto.Data!.Length);
尝试上传同一文件的块的两个同时请求将损坏内存流,因为您没有对内存流设置任何锁定。
该方法也是不正确的,您正在传输所有块并将其保存在内存中。理想情况下,您应该将块保存在文件中,并将一个文件作为一个小的独立文件保存在服务器上,这样它就不会损坏。每个文件应根据客户请求有一个唯一的名称。
S3 已经支持部分上传,您可以利用 S3 自己的上传 API 来完成您想要做的事情。