保存大文件到数据库中

本文分享一下其中一些重点的技术细节

其中一个关键的技术就是将文件使用二进制的方式存放在数据库的varbinary(max)的字段中。该字段最大允许的长度为2GB。

对于一些小文件,我们可以一次性读取它的所有字节,然后一次提交到数据库

/// <summary>
/// 这个方法演示了如何一次提交所有的字节。这样导致的结果是:应用程序立即需要申请等同于文件大小的内存
/// </summary>
static void SubmitFileByOnce() {
    string file = @"F:/功夫熊猫.rmvb";//文件大小为519MB
    byte[] buffer = File.ReadAllBytes(file);
    using (SqlConnection conn = new SqlConnection("server=(local);database=demo;integrated security=true")) {
        using (SqlCommand cmd = conn.CreateCommand())
        {
            cmd.CommandText = "INSERT INTO Files(FileName,FileContents) VALUES(@fileName,@fileContents)";
            cmd.Parameters.AddRange(
                new[]
                {
                    new SqlParameter("@fileName",file),
                    new SqlParameter("@fileContents",buffer)
                });

            conn.Open();
            cmd.ExecuteNonQuery();
            conn.Close();
        }
    }
}

但是,上面的方法有几个问题,主要体现在如果文件比较大的话

1. 它需要一次性很大的内存,具体数据等同于文件大小。因为File.ReadAllBytes方法是将所有字节全部读入到内存。

2. 它会导致提交失败,就是因为数据太大了。数据库也会拒绝。

那么,我就对这个方法做了一下改进,将文件拆分为5MB一段,也就是说,此时每次申请的内存只有5MB。这就大大地提高了可用性。

/// <summary>
  /// 这个方法是将文件切分为5MB的块,每次只是提交5MB,所以可能多次提交,但内存占用就比较小
  /// </summary>
  static void SubmitFileStepByStep() {
      string file = @"F:/功夫熊猫.rmvb";//以这个文件为例,大小为519MB,一共需要的时间大约94秒。还是有点慢的,所以还可能需要进行压缩
      FileStream fs = new FileStream(file, FileMode.Open);

      byte[] buffer = new byte[5 * 1024 * 1024];
      int readCount;
      using (SqlConnection conn = new SqlConnection("server=(local);database=demo;integrated security=true"))
      {
          conn.Open();

          while ((readCount = fs.Read(buffer, 0, buffer.Length)) > 0)
          {

              using (SqlCommand cmd = conn.CreateCommand())
              {
                  cmd.CommandText = "INSERT INTO Files(FileName,FileContents) VALUES(@fileName,@fileContents)";
                  cmd.Parameters.AddRange(
                      new[]
                  {
                      new SqlParameter("@fileName",file),
                      new SqlParameter("@fileContents",buffer)
                  });

                  cmd.ExecuteNonQuery();
              }

          }

          conn.Close();

      }
  }

这样的话,有一个后果就是一个文件,可能在数据库中会有多条记录。所以在读取的时候,我们需要对其进行合并

static void DownloadFile() {
    string file = @"F:/功夫熊猫.rmvb";
    string destfile = @"E:/Temp/Temp.wmv";
    using (SqlConnection conn = new SqlConnection("server=(local);database=demo;integrated security=true"))
    {
        using (SqlCommand cmd = conn.CreateCommand())
        {
            cmd.CommandText = "SELECT FileContents FROM Files WHERE FileName=@fileName";
            cmd.Parameters.AddRange(
                new[]
                {
                    new SqlParameter("@fileName",file),
                });

            conn.Open();
            SqlDataReader reader = cmd.ExecuteReader();
            FileStream fs = new FileStream(destfile, FileMode.Append, FileAccess.Write);

            while (reader.Read())
            {
                byte[] buffer = (byte[])reader[0];
                fs.Write(buffer, 0, buffer.Length);
            }

            fs.Close();
            reader.Close();
            conn.Close();
        }
    }
}

 

 

本文转贴自:保存大文件到数据库中http://www.cnblogs.com/chenxizhang/archive/2009/07/28/1532722.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值