В настоящее время вы работаете в автономном режиме; ожидается повторное подключение к Интернету
Войти

Браузер не поддерживается

Чтобы использовать веб-сайт, обновите браузер.

Обновите браузер до последней версии Internet Explorer

Чтение и запись файла в поля типа BLOB путем разделения на фрагменты с помощью ADO.NET и Visual C# .NET

Версия данной статьи для Microsoft Visual Basic .NET: 317034.
Версия данной статьи для Microsoft Visual C++ .NET: 317044.
Аннотация
В данной статье рассматривается использование инструкций READTEXT и UPDATETEXT сервера Microsoft SQL Server для чтения и записи данных в поля типа BLOB таблицы базы данных.

Ограничения, существующие в сети, могут приводить к тому, что файл, хранящийся в поле типа BLOB, невозможно считать целиком. Такие файлы можно разбить на фрагменты, которые необходимо считывать по отдельности, а затем объединять в файл. Однако методы GetChunk и AppendChunk поставщиков данных ADO.NET нельзя применять к объектам типа Recordset в DAO (Data Access Object) и ADO (ActiveX Data Objects). В этой статье описан альтернативный способ извлечения данных.

Примечания
  • Данная статья содержит примеры для поставщиков данных SqlClient Data Provider и OLE DB .NET Data Provider. Единственное отличие между ними (за исключением имени класса) заключается в строках подключения и объявлении параметров SQL. При использовании инструкций READTEXT и UPDATETEXT применяется аналогичный подход.
  • В таблице Categories учебной базы данных Northwind отсутствует запись со значением «Test». Необходимо с помощью обозревателя серверов (или аналогичного средства) добавить запись, в которой полю CategoryName присвоено значение Test. Если после изучения приведенных примеров нужно будет удалить эту запись, введите следующие команды в программе SQL Query Analyzer и нажмите клавишу F5:
    use Northwinddelete from Categories where CategoryName = 'Test'					

Ниже перечислены требуемые параметры оборудования и сети, а также необходимое программное обеспечение, пакеты обновления, знания и опыт.
  • Microsoft Windows 2000 Professional, Windows 2000 Server, Windows 2000 Advanced Server или Microsoft Windows NT 4.0 Server.
  • Microsoft Visual Studio .NET.
  • Microsoft SQL Server 7.0 (или более поздняя версия).
Для понимания материала, представленного в статье, необходимо знание синтаксиса и основ использования ADO.NET.

  1. Запустите приложение SQL Query Analyzer.
  2. Введите следующую команду и нажмите клавишу F5, чтобы использовать по умолчанию базу данных Northwind:
    use Northwind
  3. Введите следующую команду и нажмите клавишу F5, чтобы вставить новую запись в таблицу Categories базы данных Northwind:
    Insert into categories(categoryname) values ('Test')
    Примечание. Эту запись следует добавлять только в том случае, если примеры, приведенные в данной статье, не должны изменять данные в таблице.
  4. Запустите Visual Studio .NET и создайте проект Visual C# .NET Windows Application.
  5. Поместите следующие две строки кода в начало файла Form1.cs, чтобы добавить ссылку на System.Data.SQLClient и System.Data.OleDb:
    using System.Data.SqlClient;using System.Data.OleDb;
  6. Поместите на форму Form1 четыре кнопки. Присвойте свойству Text этих кнопок значения SQLBlob2File, OlDbBlob2File, File2OleDbBlob и File2SqlBlob соответственно.
  7. В объявление класса Form1 добавьте следующие строки:
    string destfilepath;string sourcefilepath;					
  8. Добавьте следующий код к обработчику события Load данной формы:
    destfilepath = @"c:\mytest.bmp";sourcefilepath = @"c:\windows\coffee bean.bmp";					
  9. Вызовите процедуры событий Click для каждой кнопки:
    // Click event for the button labeled SqlBlob2File.SqlChunkBlob2File(destfilepath);// Click event for the button labeled OLDbBlob2File.OlDbChunkBlob2File(destfilepath);// Click event for the button labeled File2OleDbBlob.ChunkFile2OleDbBlob(sourcefilepath);//Click event for the button labeled File2SqlBlob.ChunkFile2SqlBlob(sourcefilepath);					
  10. Поместите в файл Form1 следующие четыре функции:
    public void SqlChunkBlob2File(string DestFilePath){   try   {	int PictureCol  = 0;  // position of Picture column in DataReader	int BUFFER_LENGTH  = 32768; // chunk size	SqlConnection cn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;");				// Make sure Photo is non-NULL and return TEXTPTR to it.				SqlCommand cmdGetPointer = new SqlCommand("SELECT @Pointer=TEXTPTR(Picture), @Length=DataLength(Picture) FROM Categories WHERE CategoryName='Test'", cn);	SqlParameter PointerOutParam = cmdGetPointer.Parameters.Add("@Pointer", SqlDbType.VarBinary, 100);	PointerOutParam.Direction = ParameterDirection.Output;	SqlParameter LengthOutParam  = cmdGetPointer.Parameters.Add("@Length", SqlDbType.Int);	LengthOutParam.Direction = ParameterDirection.Output;	cn.Open();	cmdGetPointer.ExecuteNonQuery();	if(PointerOutParam.Value == null) 	{		cn.Close();		// Add code to handle NULL BLOB.		return;	}				// Set up READTEXT command, parameters, and open BinaryReader.				SqlCommand cmdReadBinary = new SqlCommand("READTEXT Categories.Picture @Pointer @Offset @Size HOLDLOCK", cn);	SqlParameter PointerParam  = cmdReadBinary.Parameters.Add("@Pointer", SqlDbType.Binary, 16);	SqlParameter OffsetParam  = cmdReadBinary.Parameters.Add("@Offset", SqlDbType.Int);	SqlParameter SizeParam  = cmdReadBinary.Parameters.Add("@Size", SqlDbType.Int);	SqlDataReader dr; 	System.IO.FileStream fs = new System.IO.FileStream(DestFilePath, System.IO.FileMode.Create, System.IO.FileAccess.Write);	int Offset= 0;	OffsetParam.Value = Offset;	Byte []Buffer = new Byte[BUFFER_LENGTH ];				// Read buffer full of data and write to the file stream.				do	{		PointerParam.Value = PointerOutParam.Value;						// Calculate buffer size - may be less than BUFFER_LENGTH for last block.						if( (Offset + BUFFER_LENGTH) >= System.Convert.ToInt32(LengthOutParam.Value)) 			SizeParam.Value = System.Convert.ToInt32(LengthOutParam.Value) - Offset;		else SizeParam.Value = BUFFER_LENGTH;						dr = cmdReadBinary.ExecuteReader(CommandBehavior.SingleResult);		dr.Read();		dr.GetBytes(PictureCol, 0, Buffer, 0, System.Convert.ToInt32(SizeParam.Value));		dr.Close();		fs.Write(Buffer, 0, System.Convert.ToInt32(SizeParam.Value));		Offset += System.Convert.ToInt32(SizeParam.Value);		OffsetParam.Value = Offset;	}while(Offset < System.Convert.ToInt32(LengthOutParam.Value));	fs.Close();	cn.Close();   }   catch(SqlException ex)   {   MessageBox.Show (ex.Message);   }}public void OleDbChunkBlob2File(string DestFilePath){   try   {	int PictureCol= 0; // Position of picture column in DataReader.	int BUFFER_LENGTH = 32768;// Chunk size.	OleDbConnection cn = new OleDbConnection("Provider=SQLOLEDB;Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;");				// Make sure Photo is non-NULL and return TEXTPTR to it.			OleDbCommand cmdGetPointer = new OleDbCommand("SELECT ?=TEXTPTR(Picture), ?=DataLength(Picture) FROM Categories WHERE CategoryName='Test'", cn);	OleDbParameter PointerOutParam =  cmdGetPointer.Parameters.Add("@Pointer", OleDbType.VarBinary, 100);	PointerOutParam.Direction = ParameterDirection.Output;	OleDbParameter LengthOutParam = cmdGetPointer.Parameters.Add("@Length", OleDbType.Integer);	LengthOutParam.Direction = ParameterDirection.Output;	cn.Open();	cmdGetPointer.ExecuteNonQuery();	if(PointerOutParam.Value == null)	{		cn.Close();		// Add code to deal with NULL BLOB.		return;	}				// Set up READTEXT command, parameters, and open BinaryReader.				OleDbCommand cmdReadBinary = new OleDbCommand("READTEXT Categories.Picture ? ? ? HOLDLOCK", cn);	OleDbParameter PointerParam  = cmdReadBinary.Parameters.Add("@Pointer", OleDbType.Binary, 16);	OleDbParameter OffsetParam  = cmdReadBinary.Parameters.Add("@Offset", OleDbType.Integer);	OleDbParameter SizeParam  = cmdReadBinary.Parameters.Add("@Size", OleDbType.Integer);	OleDbDataReader dr;	System.IO.FileStream fs = new System.IO.FileStream(DestFilePath, System.IO.FileMode.Create, System.IO.FileAccess.Write);	int Offset= 0;	OffsetParam.Value = Offset;	Byte[] Buffer = new Byte[BUFFER_LENGTH];				//Read buffer full of data and write to the file stream.				do	{		PointerParam.Value = PointerOutParam.Value;						// Calculate buffer size - may be less than BUFFER_LENGTH for last block.						if((Offset + BUFFER_LENGTH) >= System.Convert.ToInt32(LengthOutParam.Value))			SizeParam.Value = System.Convert.ToInt32(LengthOutParam.Value) - Offset;		else SizeParam.Value = BUFFER_LENGTH;						dr = cmdReadBinary.ExecuteReader(CommandBehavior.SingleResult);		dr.Read();		dr.GetBytes(PictureCol, 0, Buffer, 0, System.Convert.ToInt32(SizeParam.Value));		dr.Close();		fs.Write(Buffer, 0, System.Convert.ToInt32(SizeParam.Value));		Offset += System.Convert.ToInt32(SizeParam.Value);		OffsetParam.Value = Offset;	}while( Offset < System.Convert.ToInt32(LengthOutParam.Value));	fs.Close();	cn.Close();   }   catch(OleDbException ex)   {   MessageBox.Show (ex.Message);   }}				
  11. Нажмите клавишу F5, чтобы запустить программу. Нажмите кнопку File2OleDbBlob, чтобы загрузить образ в базу данных.

Следующие функции используют DataReader и команду READTEXT сервера SQL Server, чтобы считать значение типа BLOB в набор строк, имеющий одну строку и один столбец. При этом используются две команды, первая из которых определяет размер поля типа BLOB и указатель на его размещение, а вторая выполняет команду READTEXT. Команда READTEXT считывает фрагмент данных в массив байтов и увеличивает значение переменной Offset. Массив байтов записывается на диск с помощью объекта System.IO.Filesream.

Следующие функции используют команду UPDATETEXT сервера SQL Server и объекты Command и Parameter, чтобы сохранить фрагменты данных из массива байтов в поле типа BLOB. При использовании этого метода поле типа BLOB не может быть пустым, поэтому перед получением значения TEXTPTR в это поле помещается один байт данных. При первом выполнении команды UPDATETEXT переменной DeleteParam.Value присваивается значение 1. При этом байт данных, ранее записанный в поле типа BLOB, удаляется. Команда UPDATETEXT выполняется несколько раз. При каждом выполнении значение переменной Offset увеличивается на величину, равную размеру буфера.
private void ChunkFile2SqlBlob(string SourceFilePath){   try   {	int BUFFER_LENGTH = 32768; // Chunk size.	SqlConnection cn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;");				// Make sure Photo is non-NULL and return TEXTPTR to it.			SqlCommand cmdGetPointer = new SqlCommand("SET NOCOUNT ON;UPDATE Categories SET Picture = 0x0 WHERE CategoryName='Test';" +					"SELECT @Pointer=TEXTPTR(Picture) FROM Categories WHERE CategoryName='Test'", cn);	SqlParameter PointerOutParam  = cmdGetPointer.Parameters.Add("@Pointer", SqlDbType.VarBinary, 100);	PointerOutParam.Direction = ParameterDirection.Output;	cn.Open();	cmdGetPointer.ExecuteNonQuery();			// Set up UPDATETEXT command, parameters, and open BinaryReader.				SqlCommand cmdUploadBinary = new SqlCommand("UPDATETEXT Categories.Picture @Pointer @Offset @Delete WITH LOG @Bytes", cn);	SqlParameter PointerParam  = cmdUploadBinary.Parameters.Add("@Pointer", SqlDbType.Binary, 16);	SqlParameter OffsetParam= cmdUploadBinary.Parameters.Add("@Offset", SqlDbType.Int);	SqlParameter DeleteParam = cmdUploadBinary.Parameters.Add("@Delete", SqlDbType.Int);	DeleteParam.Value = 1;  // delete 0x0 character				SqlParameter BytesParam  = cmdUploadBinary.Parameters.Add("@Bytes", SqlDbType.Binary, BUFFER_LENGTH);	System.IO.FileStream fs = new System.IO.FileStream(SourceFilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);	System.IO.BinaryReader br = new System.IO.BinaryReader(fs);	int Offset = 0;	OffsetParam.Value = Offset;				// Read buffer full of data and execute UPDATETEXT statement.				Byte [] Buffer = br.ReadBytes(BUFFER_LENGTH);	while(Buffer.Length > 0)	{		PointerParam.Value = PointerOutParam.Value;		BytesParam.Value = Buffer;		cmdUploadBinary.ExecuteNonQuery();		DeleteParam.Value = 0; //Do not delete any other data.		Offset += Buffer.Length;		OffsetParam.Value = Offset;		Buffer = br.ReadBytes(BUFFER_LENGTH);	}	br.Close();	fs.Close();	cn.Close();   }   catch(SqlException ex)   {   MessageBox.Show (ex.Message);   }			}public void ChunkFile2OleDbBlob(string SourceFilePath){   try   {	         int BUFFER_LENGTH = 32768; // chunk size	OleDbConnection cn = new OleDbConnection("Provider=SQLOLEDB;Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;");			// Make sure Photo is non-NULL and return TEXTPTR to it.			OleDbCommand cmdGetPointer = new OleDbCommand("SET NOCOUNT ON;UPDATE Categories SET Picture = 0x0 WHERE CategoryName='Test';" +				"SELECT ?=TEXTPTR(Picture) FROM Categories WHERE CategoryName='Test'", cn);	OleDbParameter PointerOutParam = cmdGetPointer.Parameters.Add("@Pointer", OleDbType.VarBinary, 100);	PointerOutParam.Direction = ParameterDirection.Output;	cn.Open();	cmdGetPointer.ExecuteNonQuery();				// Set up UPDATETEXT command, parameters, and open BinaryReader.				OleDbCommand cmdUploadBinary = new OleDbCommand("UPDATETEXT Categories.Picture ? ? ? WITH LOG ?", cn);	OleDbParameter PointerParam = cmdUploadBinary.Parameters.Add("@Pointer", OleDbType.Binary, 16);	OleDbParameter OffsetParam = cmdUploadBinary.Parameters.Add("@Offset", OleDbType.Integer);	OleDbParameter DeleteParam   = cmdUploadBinary.Parameters.Add("@Delete", OleDbType.Integer);	DeleteParam.Value = 1;  // delete 0x0 character	OleDbParameter BytesParam = cmdUploadBinary.Parameters.Add("@Bytes", OleDbType.Binary, BUFFER_LENGTH);	System.IO.FileStream fs = new System.IO.FileStream(SourceFilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);	System.IO.BinaryReader br = new System.IO.BinaryReader(fs);	int Offset= 0;	OffsetParam.Value = Offset;				// Read buffer full of data and execute UPDATETEXT statement.			         Byte[] Buffer = br.ReadBytes(BUFFER_LENGTH);	while(Buffer.Length > 0)	{		PointerParam.Value = PointerOutParam.Value;		BytesParam.Value = Buffer;		cmdUploadBinary.ExecuteNonQuery();		DeleteParam.Value = 0;// Do not delete any other data.		Offset += Buffer.Length;		OffsetParam.Value = Offset;		Buffer = br.ReadBytes(BUFFER_LENGTH);	}	br.Close();	fs.Close();	cn.Close();		   }   catch(OleDbException ex)   {   MessageBox.Show (ex.Message);   }}				
Примечания
  • Примеры, приведенные в данной статье, не предназначены для использования с полями типа LongVarChar или LongVarWChar.
  • Измените строку подключения и параметры SQL таким образом, чтобы они соответствовали используемому серверу. Добавьте процедуру, проверяющую, возвращена ли в ответ на запрос хотя бы одна запись.
  • Команды READTEXT и UPDATETEXT являются командами сервера Microsoft SQL Server. Другие системы управления базами данных могут иметь команды, выполняющие аналогичные функции.
Ссылки
Дополнительные сведения о чтении и записи данных без разбиения на фрагменты см. в следующих статьях базы данных Майкрософт.
316887 Чтение и запись файла в поля типа BLOB с помощью ADO.NET и Visual Basic .NET
317017 Чтение и запись файла в поля типа BLOB с помощью ADO.NET и Visual C++ .NET
Дополнительные сведения о работе с полями типа BLOB в ADO.NET см. на веб-узле MSDN по следующему адресу:
kbblob kbnetsearch kbchunking
Свойства

Номер статьи: 317043 — последний просмотр: 06/28/2004 18:58:33 — редакция: 2.1

  • Microsoft ADO.NET (included with the .NET Framework)
  • Microsoft ADO.NET 1.1
  • Microsoft Visual C# .NET 2002 Standard Edition
  • Microsoft Visual C# .NET 2003 Standard Edition
  • kbsystemdata kbsqlclient kbhowtomaster KB317043
Отзывы и предложения
<\/script>");