【问题标题】:Downloading large files, saved in Database下载大文件,保存在数据库中
【发布时间】:2012-08-21 20:57:51
【问题描述】:

我们有很多文件,在我们的 SQL Server 数据库中保存为二进制文件。 我制作了一个 .ashx 文件,将这些文件传递给用户。 不幸的是,当文件变得相当大时,它会失败,并出现以下错误:

算术运算中的上溢或下溢

我假设它内存不足,因为我将二进制文件加载到一个字节[]中。

所以,我的问题是,当它来自数据库表时,我怎样才能使这个功能以块的形式读取(也许?)? Response.TransmitFile() 似乎也是一个不错的选择,但同样,这如何与数据库一起使用?

下面代码中的 DB.GetReposFile() 从数据库中获取文件。条目有多个字段: 文件名、内容类型、日期戳和文件内容为 varbinary。

这是我的功能,传递文件:

context.Response.Clear();
try
{
    if (!String.IsNullOrEmpty(context.Request.QueryString["id"]))
    {
        int id = Int32.Parse(context.Request.QueryString["id"]);
        DataTable dtbl = DB.GetReposFile(id);
        string FileName = dtbl.Rows[0]["FileName"].ToString();
        string Extension = FileName.Substring(FileName.LastIndexOf('.')).ToLower();
        context.Response.ContentType = ReturnExtension(Extension);
        context.Response.AddHeader("Content-Disposition", "attachment; filename=" + FileName);

        byte[] buffer = (byte[])dtbl.Rows[0]["FileContent"];
        context.Response.OutputStream.Write(buffer, 0, buffer.Length);
    }
    else
    {
        context.Response.ContentType = "text/html";
        context.Response.Write("<p>Need a valid id</p>");
    }
}
catch (Exception ex)
{
    context.Response.ContentType = "text/html";
    context.Response.Write("<p>" + ex.ToString() + "</p>");
}

更新: 我最终得到的功能是下面列出的功能。 正如 Tim 所提到的,DB.GetReposFileSize() 只是获取内容 Datalength。 我在原始代码中调用了这个函数,而不是这两行:

byte[] buffer = (byte[])dtbl.Rows[0]["FileContent"];
context.Response.OutputStream.Write(buffer, 0, buffer.Length);

新增下载功能:

private void GetFileInChunks(HttpContext context, int ID)
    {
        //string path = @"c:\somefile.txt";
        //FileInfo file = new FileInfo(path);
        int len = DB.GetReposFileSize(ID);
        context.Response.AppendHeader("content-length", len.ToString());
        context.Response.Buffer = false;


        //Stream outStream = (Stream)context.Response.OutputStream;

        SqlConnection conn = null;
        string strSQL = "select FileContent from LM_FileUploads where ID=@ID";
        try
        {
            DB.OpenDB(ref conn, DB.DatabaseConnection.PDM);
            SqlCommand cmd = new SqlCommand(strSQL, conn);
            cmd.Parameters.AddWithValue("@ID", ID);

            SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess);
            reader.Read();
            byte[] buffer = new byte[1024];
            int bytes;
            long offset = 0;

            while ((bytes = (int)reader.GetBytes(0, offset, buffer, 0, buffer.Length)) > 0)
            {
                // TODO: do something with `bytes` bytes from `buffer`
                context.Response.OutputStream.Write(buffer, 0, buffer.Length);

                offset += bytes;
            }
        }

        catch (Exception ex)
        {
            throw ex;
        }
        finally
        {
            DB.CloseDB(ref conn);
        }
    }

【问题讨论】:

  • 看看这个答案:stackoverflow.com/a/609151/284240
  • @TimSchmelter,如何从我的数据库字段中分块读取它?我没有要读取的文件路径,而是 varbinary 字段。
  • 你可以使用SqlFileStream
  • @TimSchmelter,看起来很有趣,但似乎需要重新配置我们的数据库。我不确定我能不能完成。
  • @TimSchmelter,应用您提到的功能(在您编辑之前,使用 SQLDataReader),以及有关 Flash 流的链接使其工作。如果你写一个答案,我一定会标记它。

标签: c# asp.net exception-handling download ashx


【解决方案1】:

您可以使用DATALENGTH 获取VARBINARY 的大小并使用SqldataReader 进行流式传输,例如Read-或ReadBytes-方法。

查看此答案以查看实现:Best way to stream files in ASP.NET

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-19
    • 1970-01-01
    • 2018-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多