位置: 文档库 > C#(.NET) > C#将文件上传、下载(以二进制流保存到数据库)

C#将文件上传、下载(以二进制流保存到数据库)

曼德拉 上传于 2021-04-24 23:48

C#将文件上传、下载(以二进制流保存到数据库)》

在.NET开发中,文件存储是常见的业务需求。传统方式通常将文件保存在服务器本地文件系统,但这种方式存在文件分散管理困难、难以实现分布式存储等缺点。将文件以二进制流形式存储到数据库中,可以更方便地实现集中管理、权限控制和事务一致性。本文将详细介绍如何使用C#实现文件的上传、下载功能,并将文件内容以二进制流形式保存到数据库中。

一、数据库设计

首先需要设计一个用于存储文件信息的数据库表。通常需要包含以下字段:

CREATE TABLE FileStorage (
    FileId INT PRIMARY KEY IDENTITY(1,1),
    FileName NVARCHAR(255) NOT NULL,
    FileType NVARCHAR(100) NOT NULL,
    FileSize BIGINT NOT NULL,
    FileData VARBINARY(MAX) NOT NULL,
    UploadTime DATETIME NOT NULL DEFAULT GETDATE(),
    Description NVARCHAR(500)
)

这个表结构包含文件ID、文件名、文件类型、文件大小、文件二进制数据、上传时间和描述信息。其中FileData字段使用VARBINARY(MAX)类型,可以存储最大2GB的二进制数据。

二、文件上传实现

文件上传功能需要完成以下几个步骤:

1. 接收客户端上传的文件

2. 读取文件为二进制流

3. 将文件信息保存到数据库

以下是完整的实现代码:

public class FileUploadResult
{
    public bool Success { get; set; }
    public string Message { get; set; }
    public int FileId { get; set; }
}

public class FileService
{
    private readonly string _connectionString;

    public FileService(string connectionString)
    {
        _connectionString = connectionString;
    }

    public FileUploadResult UploadFile(HttpPostedFileBase file, string description = "")
    {
        var result = new FileUploadResult { Success = false };

        try
        {
            if (file == null || file.ContentLength == 0)
            {
                result.Message = "请选择要上传的文件";
                return result;
            }

            if (file.ContentLength > 10 * 1024 * 1024) // 限制为10MB
            {
                result.Message = "文件大小不能超过10MB";
                return result;
            }

            // 读取文件为二进制
            byte[] fileData;
            using (var binaryReader = new BinaryReader(file.InputStream))
            {
                fileData = binaryReader.ReadBytes(file.ContentLength);
            }

            // 保存到数据库
            using (var connection = new SqlConnection(_connectionString))
            {
                connection.Open();

                var command = new SqlCommand(
                    "INSERT INTO FileStorage (FileName, FileType, FileSize, FileData, Description) " +
                    "VALUES (@FileName, @FileType, @FileSize, @FileData, @Description); " +
                    "SELECT SCOPE_IDENTITY()",
                    connection);

                command.Parameters.AddWithValue("@FileName", file.FileName);
                command.Parameters.AddWithValue("@FileType", file.ContentType);
                command.Parameters.AddWithValue("@FileSize", file.ContentLength);
                command.Parameters.AddWithValue("@FileData", fileData);
                command.Parameters.AddWithValue("@Description", description);

                var fileId = Convert.ToInt32(command.ExecuteScalar());

                result.Success = true;
                result.Message = "文件上传成功";
                result.FileId = fileId;
            }
        }
        catch (Exception ex)
        {
            result.Message = $"上传失败: {ex.Message}";
        }

        return result;
    }
}

ASP.NET MVC控制器中调用上述服务:

[HttpPost]
public ActionResult Upload(HttpPostedFileBase file, string description)
{
    var fileService = new FileService(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString);
    var result = fileService.UploadFile(file, description);

    if (result.Success)
    {
        return Json(new { success = true, fileId = result.FileId });
    }
    else
    {
        return Json(new { success = false, message = result.Message });
    }
}

三、文件下载实现

文件下载功能需要完成以下几个步骤:

1. 从数据库查询文件信息

2. 将二进制数据转换为文件流

3. 设置正确的响应头

4. 将文件流写入响应

以下是完整的实现代码:

public class FileDownloadResult
{
    public bool Success { get; set; }
    public string Message { get; set; }
    public byte[] FileData { get; set; }
    public string FileName { get; set; }
    public string FileType { get; set; }
}

public class FileService
{
    // ... 前面的UploadFile方法 ...

    public FileDownloadResult DownloadFile(int fileId)
    {
        var result = new FileDownloadResult { Success = false };

        try
        {
            using (var connection = new SqlConnection(_connectionString))
            {
                connection.Open();

                var command = new SqlCommand(
                    "SELECT FileName, FileType, FileData FROM FileStorage WHERE FileId = @FileId",
                    connection);

                command.Parameters.AddWithValue("@FileId", fileId);

                using (var reader = command.ExecuteReader())
                {
                    if (reader.Read())
                    {
                        result.FileName = reader["FileName"].ToString();
                        result.FileType = reader["FileType"].ToString();
                        result.FileData = (byte[])reader["FileData"];
                        result.Success = true;
                    }
                    else
                    {
                        result.Message = "文件不存在";
                    }
                }
            }
        }
        catch (Exception ex)
        {
            result.Message = $"下载失败: {ex.Message}";
        }

        return result;
    }
}

在ASP.NET MVC控制器中实现下载动作:

[HttpGet]
public ActionResult Download(int fileId)
{
    var fileService = new FileService(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString);
    var result = fileService.DownloadFile(fileId);

    if (!result.Success)
    {
        return Content(result.Message);
    }

    // 设置响应头
    Response.Clear();
    Response.ContentType = result.FileType;
    Response.AddHeader("Content-Disposition", $"attachment; filename={HttpUtility.UrlEncode(result.FileName)}");
    Response.AddHeader("Content-Length", result.FileData.Length.ToString());

    // 写入文件数据
    Response.BinaryWrite(result.FileData);
    Response.End();

    return new EmptyResult();
}

四、前端实现示例

前端可以使用HTML5的File API和AJAX实现文件上传:

@using (Html.BeginForm("Upload", "File", FormMethod.Post, new { enctype = "multipart/form-data", id = "uploadForm" }))
{
    
}

五、性能优化考虑

1. 大文件处理:对于大文件(超过100MB),建议采用分块上传的方式,避免内存溢出。

2. 数据库优化:VARBINARY(MAX)字段在SQL Server中默认存储在表外,不会显著影响表扫描性能。但大量大文件存储仍可能影响数据库性能,考虑使用FILESTREAM特性。

3. 缓存策略:对于频繁下载的文件,可以实现缓存机制减少数据库访问。

4. 异步处理:上传下载操作可以改为异步方式,提高用户体验。

六、安全考虑

1. 文件类型验证:限制允许上传的文件类型,防止上传恶意文件。

private bool IsAllowedFileType(string fileName)
{
    var allowedExtensions = new[] { ".jpg", ".jpeg", ".png", ".gif", ".pdf", ".doc", ".docx", ".xls", ".xlsx" };
    var extension = Path.GetExtension(fileName).ToLower();
    return allowedExtensions.Contains(extension);
}

2. 文件大小限制:限制上传文件大小,防止拒绝服务攻击。

3. 病毒扫描:对于生产环境,建议集成病毒扫描功能。

4. 权限控制:实现基于角色的文件访问控制。

七、完整示例项目结构

FileStorageDemo/
├── Controllers/
│   └── FileController.cs
├── Models/
│   ├── FileUploadResult.cs
│   └── FileDownloadResult.cs
├── Services/
│   └── FileService.cs
├── Views/
│   └── File/
│       ├── Index.cshtml
│       └── _FileList.cshtml
├── Scripts/
│   └── file.js
└── Web.config

八、总结

本文详细介绍了如何使用C#和.NET框架实现文件的上传和下载功能,并将文件以二进制流形式存储在数据库中。主要内容包括:

1. 数据库表设计,使用VARBINARY(MAX)类型存储文件数据

2. 文件上传实现,包括前端表单和后端服务

3. 文件下载实现,正确设置响应头和内容类型

4. 前端实现示例,使用AJAX实现无刷新上传

5. 性能优化和安全考虑

这种实现方式适合需要集中管理文件、实现事务一致性或需要与业务数据紧密关联的场景。对于非常大的文件或需要高性能访问的场景,可能需要考虑其他存储方案。

关键词:C#、.NET文件上传、文件下载、二进制流、数据库存储、VARBINARY、ASP.NET MVC、AJAX、性能优化、安全考虑

简介:本文详细介绍了在C#(.NET)环境中实现文件上传和下载功能,并将文件以二进制流形式存储到数据库中的完整方案。内容涵盖数据库设计、前后端代码实现、性能优化和安全考虑等方面,提供了从基础实现到高级优化的全面指导。

《C#将文件上传、下载(以二进制流保存到数据库).doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档