如何使用.NET数据提供程序在firebird db中使用大文件(1Gb)更新二进制blob字段?

时间:2014-04-17 13:45:58

标签: c# sql firebird

我想将一个大小为1Gb的大文件上传到我的firebird数据库。我一直在收到一个System.OutOfMemoryException'抛出下面的代码。

FbTransaction trans = conn.BeginTransaction();
string updateSQL = string.Format( @"UPDATE {0} SET {1} = :DATA WHERE {2} RETURNING DATA", tableName, colName, whereStr );
using( FbCommand getBlobCmd = new FbCommand( updateSQL, conn ) )
{
  try
  {
    getBlobCmd.Transaction = trans;
    FbParameter parBlob = new FbParameter( "DATA", FbDbType.Binary );
    parBlob.Direction = ParameterDirection.Output;
    parBlob.Value = File.ReadAllBytes(filePath); //System.OutOfMemoryException
    getBlobCmd.Parameters.Add( parBlob );
    getBlobCmd.ExecuteNonQuery();
    trans.Commit();
  }
  catch
  {
    if( trans != null )
      trans.Rollback();
  }
}

我知道我需要以块的形式写入数据。但是.NET数据提供程序中没有具有类似功能的类。在这种情况下我需要使用什么?谢谢!

3 个答案:

答案 0 :(得分:1)

目前您基本上只有一个选项(假设您想通过.NET提供程序)。将您的应用切换到x64(如果您还没有完成)并购买足够的RAM(或制作大量交换文件)。我知道,这不是最佳解决方案。

你也可以对http://tracker.firebirdsql.org/browse/DNET-279表示爱意。然后你可以上传基本尺寸无限的文件。

答案 1 :(得分:0)

我通过在BlobBase.cs中添加方法解决了这个问题:

    public void Write( Stream stream )
    { 
        try
        {
            this.Create();

            byte[] tmpBuffer = null;

            int length = (int)stream.Length;
            int offset  = 0;
            int chunk   = length >= this.segmentSize ? this.segmentSize : length;

            tmpBuffer = new byte[chunk];

            while( length > 0 )
            {
                if( chunk > length )
                {
                    chunk = ( int )length;
                    tmpBuffer = new byte[ chunk ];
                }

                stream.Read( tmpBuffer, 0, chunk );
                this.PutSegment( tmpBuffer );

                offset += chunk;
                length -= chunk;
            }

            this.Close();
        }
        catch (Exception)
        {
            // Cancel the blob and rethrow the exception
            this.Cancel();

            throw;
        }
    }

和FbCommand.cs:

BlobBase blob = this.statement.CreateBlob();
if( this.Parameters[ index ].Value is System.IO.Stream )
{
  blob.Write( (System.IO.Stream)this.Parameters[ index ].Value );
}
else
{
   blob.Write( (byte[])this.Parameters[ index ].Value );
}

最后使用代码段:

string updateSQL = string.Format( @"UPDATE {0} SET {1} = :DATA WHERE {2}",    tableName, colName, whereStr );

using( FbCommand getBlobCmd = new FbCommand( updateSQL, conn ) )
{
  try
  {
    FbParameter parBlob = new FbParameter( "DATA", FbDbType.Binary );
    parBlob.Direction = ParameterDirection.Input;
    parBlob.Value = blobFile.InnerStream;//input FileStream
    getBlobCmd.Parameters.Add( parBlob );
    getBlobCmd.Prepare();
    getBlobCmd.ExecuteNonQuery();
  }
  catch{}
}

谢谢,求助!

答案 2 :(得分:0)

您可以编写和读取大小超过1GB的BLOB数据(文本和二进制):)

“IBProvider”+“LCPI .NET数据提供程序”具有对System.IO.Stream和System.IO.TextReader的本机支持,以避免物理内存的任何限制。

[System.IO.Stream的用法] http://www.ibprovider.com/eng/examples/lcpi_oledb_net__c001__example_0001.html

[使用System.IO.FileStream的示例] [俄文文本] http://firebirder.ru/firebird_interbase__and__system_io_stream__system_io_textreader

查看IBProvider网站上的其他类似示例,并找到与Firebird BLOB一起使用的其他高级技术:)

问候。