Разрабатывая инфраструктуру для автоматических тестов, а именно функционал отвечающий за хранения результатов тестирования в базе данных, мне необходимо было решить задачу хранения изображений в базе данных (Microsoft SQL Server). Изучив вопрос понял, что есть множество способов. Здесь рассмотрим два из них, которые я реализовал и выбрал оптимальный для себя.

Рассмотрим примеры записи картинок в базу данных и извлечение картинок из базы данных.

Хранение изображений в MS SQL в двоичном формате в ячейке с типом «image»

Создадим базу данных и таблицу:

USE [master]
GO
CREATE DATABASE [dbtest]
 ON  PRIMARY 
( NAME = N'dbtest', FILENAME = N'c:\DB\dbtest.mdf')
 LOG ON 
( NAME = N'dbtest_log', FILENAME = N'c:\DB\dbtest.ldf')
GO
USE [dbtest]
GO
CREATE TABLE [report] (
	[id] bigint NOT NULL PRIMARY KEY IDENTITY,
	[screen] IMAGE DEFAULT (0x),
	[screen_format] VARCHAR(5) DEFAULT NULL,
);

Обратите внимание на тип поля «screen».

Поместим любую картинку на диск «С». У меня картинка в формате jpg — «primer.jpg».

Создадим в Visual Studio консольное приложение. Добавим в файл «Program.cs»

using System; using System.IO; using System.Collections.Generic; using System.Data.SqlClient; using System.Data; using System.Drawing; 

Запишем изображение в базу данных методом PutImageBinaryInDb:

private static void PutImageBinaryInDb(string iFile)
{

	byte[] imageData = null;
	FileInfo fInfo = new FileInfo(iFile);
	long numBytes = fInfo.Length;
	FileStream fStream = new FileStream(iFile, FileMode.Open, FileAccess.Read);
	BinaryReader br = new BinaryReader(fStream);
	imageData = br.ReadBytes((int)numBytes);


	string iImageExtension = (Path.GetExtension(iFile)).Replace(".", "").ToLower();


	using (SqlConnection sqlConnection = new SqlConnection(@"Data Source=(localdb)\MSSQLLocalDB; Initial Catalog=dbtest; User Id=sa; Password=pass")) 
	{
		string commandText = "INSERT INTO report (screen, screen_format) VALUES(@screen, @screen_format)"; 
		SqlCommand command = new SqlCommand(commandText, sqlConnection);
		command.Parameters.AddWithValue("@screen", (object)imageData); 
		command.Parameters.AddWithValue("@screen_format", iImageExtension); 
		sqlConnection.Open();
		command.ExecuteNonQuery();
		sqlConnection.Close();
	}
}

Поместим вызов метода в Main:

static void Main(string[] args)
{
	PutImageBinaryInDb(@"C:\primer.jpg"); 
}

Запускаем приложение и проверяем базу данных. В базе должна появится запись:

Как сохранять изображения в базу данных MS SQL и извлекать изображения из базы данных (C#)

Извлечём изображение из базы данных, для этого создадим метод GetImageBinaryFromDb:

private static void GetImageBinaryFromDb()
{

	List<byte[]> iScreen = new List<byte[]>(); 
	List<string> iScreen_format = new List<string>();
	using (SqlConnection sqlConnection = new SqlConnection(@"Data Source=(localdb)\MSSQLLocalDB; Initial Catalog=dbtest; User Id=sa; Password=pass"))
	{
		sqlConnection.Open();
		SqlCommand sqlCommand = new SqlCommand();
		sqlCommand.Connection = sqlConnection;
		sqlCommand.CommandText = @"SELECT [screen], [screen_format] FROM [report] WHERE [id] = 1"; 
		SqlDataReader sqlReader = sqlCommand.ExecuteReader();
		byte[] iTrimByte = null;
		string iTrimText = null;
		while (sqlReader.Read()) 
		{
			iTrimByte = (byte[])sqlReader["screen"]; 
			iScreen.Add(iTrimByte);
			iTrimText = sqlReader["screen_format"].ToString().TrimStart().TrimEnd(); 
			iScreen_format.Add(iTrimText);
		}
		sqlConnection.Close();
	}


	byte[] imageData = iScreen[0]; 
	MemoryStream ms = new MemoryStream(imageData);
	Image newImage = Image.FromStream(ms);


	string iImageExtension = iScreen_format[0]; 
	string iImageName = @"C:\result_new" + "." + iImageExtension; 
	if (iImageExtension == "png") { newImage.Save(iImageName, System.Drawing.Imaging.ImageFormat.Png); }
	else if (iImageExtension == "jpg" || iImageExtension == "jpeg") { newImage.Save(iImageName, System.Drawing.Imaging.ImageFormat.Jpeg); }
	else if (iImageExtension == "gif") { newImage.Save(iImageName, System.Drawing.Imaging.ImageFormat.Gif); }

}

Поместим вызов метода в Main:

static void Main(string[] args)
{
	GetImageBinaryFromDb();
}

Запускаем приложение и в указанное нами место сохраняется изображение из базы.

Данный метод я использую сейчас, так как в двоичном формате данные в базе занимают места меньше примерно в 100 раз по сравнению с методом, который я опишу дальше. Но возможно кому-то может понадобится описанный далее метод.

Хранение изображений в MS SQL в формате base64 в ячейке с типом «varchar»

В данном методе мы будем конвертировать изображения в base64. Создадим новую таблицу:

USE [dbtest]

CREATE TABLE [report_base64] (
	[id] bigint NOT NULL PRIMARY KEY IDENTITY,
	[screen] VARCHAR(MAX) DEFAULT NULL,
	[screen_format] VARCHAR(5) DEFAULT NULL,
);

Обратите внимание на тип поля «screen».

Создадим метод PutImageBase64InDb:

private static void PutImageBase64InDb(string iFile)
{

	string base64String = null;
	using (Image image = Image.FromFile(iFile))
	{
		using (MemoryStream m = new MemoryStream())
		{
			image.Save(m, image.RawFormat);
			byte[] imageBytes = m.ToArray();
			base64String = Convert.ToBase64String(imageBytes);
		}
	}


	string iImageExtension = (Path.GetExtension(iFile)).Replace(".", "").ToLower();


	using (SqlConnection sqlConnection = new SqlConnection(@"Data Source=(localdb)\MSSQLLocalDB; Initial Catalog=dbtest; User Id=sa; Password=saSA")) 
	{
		string commandText = "INSERT INTO report_base64 (screen, screen_format) VALUES(@screen, @screen_format)"; 
		SqlCommand command = new SqlCommand(commandText, sqlConnection);
		command.Parameters.AddWithValue("@screen", base64String); 
		command.Parameters.AddWithValue("@screen_format", iImageExtension); 
		sqlConnection.Open();
		command.ExecuteNonQuery();
		sqlConnection.Close();
	}
}

Поместим вызов метода в Main:

static void Main(string[] args)
{
	PutImageBase64InDb(@"C:\primer.jpg"); 
}

Запускаем приложение и проверяем базу данных. В базе должна появится запись:

Как сохранять изображения в базу данных MS SQL и извлекать изображения из базы данных (C#)

Извлечём изображение из базы данных, для этого создадим метод GetImageBase64FromDb:

private static void GetImageBase64FromDb()
{

	List<string> iScreen = new List<string>(); 
	List<string> iScreen_format = new List<string>();
	using (SqlConnection sqlConnection = new SqlConnection(@"Data Source=(localdb)\MSSQLLocalDB; Initial Catalog=dbtest; User Id=sa; Password=saSA"))
	{
		sqlConnection.Open();
		SqlCommand sqlCommand = new SqlCommand();
		sqlCommand.Connection = sqlConnection;
		sqlCommand.CommandText = @"SELECT [screen], [screen_format] FROM [report_base64] WHERE [id] = 1"; 
		SqlDataReader sqlReader = sqlCommand.ExecuteReader();
		string iTrimText = null;
		while (sqlReader.Read()) 
		{
			iTrimText = sqlReader["screen"].ToString().TrimStart().TrimEnd(); 
			iScreen.Add(iTrimText);
			iTrimText = sqlReader["screen_format"].ToString().TrimStart().TrimEnd(); 
			iScreen_format.Add(iTrimText);
		}
		sqlConnection.Close();
	}


	string base64StringImage = iScreen[0]; 
	byte[] imageData = Convert.FromBase64String(base64StringImage); 
	MemoryStream ms = new MemoryStream(imageData);
	Image newImage = Image.FromStream(ms);


	string iImageExtension = iScreen_format[0]; 
	string iImageName = @"C:\result_new_base64" + "." + iImageExtension; 
	if (iImageExtension == "png") { newImage.Save(iImageName, System.Drawing.Imaging.ImageFormat.Png); }
	else if (iImageExtension == "jpg" || iImageExtension == "jpeg") { newImage.Save(iImageName, System.Drawing.Imaging.ImageFormat.Jpeg); }
	else if (iImageExtension == "gif") { newImage.Save(iImageName, System.Drawing.Imaging.ImageFormat.Gif); }

}

Поместим вызов метода в Main:

static void Main(string[] args)
{
	GetImageBase64FromDb();
}

Запускаем приложение и в указанное нами место сохраняется изображение из базы.

Вот и рассмотрели с вами методы сохранения изображения в базу данных MS SQL и извлечения изображения из базы данных. Есть ещё метод с использованием FILESTREAM, когда изображение пишется в файловую систему, но работа с ним идёт через обычное обращение к БД, но этот метод я не рассматривал, так как мне он пока не нужен.

Приложил для примера проект консольного приложения, которое содержит все описанные мной методы: скачать пример.