Подтвердить что ты не робот

Чтение SQL Varbinary Blob из базы данных

Я работаю над сохранением файлов в sql blob в столбце varbinary (max), и теперь у меня есть запасная часть вещей, которые я считаю.

Я не могу понять, как читать данные, учитывая, что я извлекаю значения своих БД с помощью хранимой процедуры. Я должен иметь доступ к данным столбца, например ds.Tables [0].Rows [ 0] [ "blobData" ]; поэтому необходимо, чтобы у меня был SQLCommand и т.д., как я видел в примерах, таких как ниже:

private void OpenFile(string selectedValue)
{
    String connStr = "...connStr";
    fileName = ddlFiles.GetItemText(ddlFiles.SelectedItem);

    using (SqlConnection conn = new SqlConnection(connStr))
    {
        conn.Open();
        using (SqlCommand cmd = conn.CreateCommand())
        {
            cmd.CommandText = "SELECT BLOBData FROM BLOBTest WHERE testid = " + selectedValue;

            using (SqlDataReader dr = cmd.ExecuteReader())
            {
                while (dr.Read())
                {
                    int size = 1024 * 1024;
                    byte[] buffer = new byte[size];
                    int readBytes = 0;
                    int index = 0;

                    using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
                    {
                        while ((readBytes = (int)dr.GetBytes(0, index, buffer, 0, size)) > 0)
                        {
                            fs.Write(buffer, 0, readBytes);
                            index += readBytes;
                        }
                    }
                }
            }
        }
    }

Есть ли более простой способ сделать это, когда я могу получить доступ к столбцу, который мне нужен, без sqlcommand?

Надеюсь, я был достаточно ясен в своем вопросе, если потом не спрошу, и я подробно остановимся!

UPDATE:

Теперь ситуация такова: у меня есть значение столбца blobData, возвращаемого моей хранимой процедурой, и может передать это в поток памяти и вызвать "LoadDocument (memStream); однако это приводит к смехотворному тексту вместо фактического отображения файла.

Теперь у меня вопрос, есть ли способ получить полный путь, включая расширение файла, хранящегося в SQL Blob? В настоящее время я изучаю использование Filetable для этого в надежде, что я смогу получить полный путь.

ОБНОВЛЕНИЕ 2:

Я пробовал создавать временный файл и читать это безрезультатно (все еще тарабарщина)

                string fileName = System.IO.Path.GetTempFileName().ToString().Replace(".tmp", fileExt);

            using (MemoryStream myMemoryStream = new MemoryStream(blobData, 0, (int)blobData.Length, false, true))
            {
                using (FileStream myFileStream1 = File.Create(fileName))
                {
                    myMemoryStream.WriteTo(myFileStream1);

                    myMemoryStream.Flush();
                    myMemoryStream.Close();

                    myFileStream1.Flush();
                    myFileStream1.Close();

                    FileInfo fi = new FileInfo(fileName);

                    Process prc = new Process();
                    prc.StartInfo.FileName = fi.FullName;
                    prc.Start();
                }
            }

Cheers, Н

4b9b3361

Ответ 1

Вы делаете это сложнее, чем нужно. Это использует MySQL только потому, что это удобно - все провайдеры работают практически одинаково. Некоторые вещи нужно будет настроить, чтобы обрабатывать очень большие элементы данных (больше серверной вещи, чем поставщик БД).

Сохранение изображения

string sql = "INSERT INTO BlobDemo (filename, fileType, fileData) VALUES (@name, @type, @data)";
byte[] imgBytes;

using (MySqlConnection dbCon = new MySqlConnection(MySQLConnStr))
using (MySqlCommand cmd = new MySqlCommand(sql, dbCon))
{  
    string ext = Path.GetExtension(filename);

    dbCon.Open();
    cmd.Parameters.Add("@name", MySqlDbType.String).Value = "ziggy";
    cmd.Parameters.Add("@data", MySqlDbType.Blob).Value = File.ReadAllBytes(filename);
    cmd.Parameters.Add("@tyoe", MySqlDbType.String).Value = ext;
    int rows = cmd.ExecuteNonQuery();
}

Данные файла передаются непосредственно поставщику БД

Есть ли способ получить полный путь, включая расширение файла, хранящегося в SQL Blob?

Нет. Ваш код и приведенный выше код сохраняют байты, составляющие изображение или любой файл.

Чтение данных Img назад

Это вернет данные обратно, сохранит их в файл и запустит соответствующее приложение:

string SQL = "SELECT itemName, itemData, itemtype FROM BlobDemo WHERE Id = @id";

string ext = "";
string tempFile = Path.Combine(@"C:\Temp\Blobs\", 
    Path.GetFileNameWithoutExtension(Path.GetTempFileName())); 

using (MySqlConnection dbCon = new MySqlConnection(MySQLConnStr))
using (MySqlCommand cmd = new MySqlCommand(SQL, dbCon))
{
    cmd.Parameters.Add("@id", MySqlDbType.Int32).Value = 14;
    dbCon.Open();

    using (MySqlDataReader rdr =  cmd.ExecuteReader())
    {
        if (rdr.Read())
        {
            ext = rdr.GetString(2);
            File.WriteAllBytes(tempFile + ext, (byte[])rdr["itemData"]);
        }
    }

    // OS run test
    Process prc = new Process();
    prc.StartInfo.FileName = tempFile + ext;
    prc.Start();
}
  • 1 Число совпадающих байтов с обратной связью
  • 1 Связанное приложение запускается с изображением
  • 1 Изображение, показанное в окне изображения

В обоих случаях File.ReadAllBytes() и File.WriteAllBytes() будут выполнять большую часть работы, независимо от типа файла.

Нет необходимости выкапывать данные 1k за раз. Если blob был чем-то вроде изображения, которое вы хотели использовать в приложении:

using (MySqlDataReader rdr = cmd.ExecuteReader())
{
    if (rdr.Read())
    {
        ext = rdr.GetString(2);
        using (MemoryStream ms = new MemoryStream((byte[])rdr["imgData"]))
        {
            picBox.Image = Image.FromStream(ms);
        }
    }
}

Байты blob могут быть переданы в memstream, и даже temp Image не нужно создавать, если вам не нужно его показывать.

В целом, потолок Cat сделал его обратно очень хорошо (изображение было 1,4 МБ, увеличено, еще один тест с 15,4 Мбайтом изображения также работал - оба они больше, чем я хотел бы сохранить в БД).

введите описание изображения здесь

В зависимости от того, как это используется, рассмотрите возможность архивирования изображений где-нибудь в файловой системе и просто сохраните имя файла - возможно, с добавленным Id, чтобы гарантировать, что имена уникальны и помогают визуально связывать их с записью. Мало того, что большие капли данных раздуваются над БД, но очевидно, что некоторые из них связаны с преобразованием в и из байтов, которых можно избежать.


Если вам нужно/нужно удалить их в какой-то момент после того, как связанное приложение будет выполнено с ними (на самом деле это не вопрос), используйте временный файл в определенном каталоге, чтобы вы могли удалить все в нем (условно 1), когда приложение заканчивается, или при запуске:

private string baseAppPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
                    "Company Name", "Product Name", "Temp Files");

Добавить имя файла Temp и фактическое расширение для отдельных файлов. Кроме того, вы можете сохранить List<string> trashCan, чтобы сохранить имя каждого создаваемого вами файла, который будет удален позже.

1 Всякий раз, когда вы удаляете их, do разрешает, чтобы все файлы были открыты в приложении, связанном с расширением.

Ответ 2

Вам нужно будет использовать SqlCommand для извлечения данных, когда данные хранятся в столбце varbinary (MAX), если вы не используете FileTable, который позволяет получить доступ к содержимому по пути UNC аналогично обычным файлам, хранящимся в файловой системе, но управляемым SQL Server.

Если размер blob может быть большим, используемая вами технология "chunk" уменьшит требования к памяти, но за счет более подробного кода. Для разумных размеров размерных блоков вы можете прочитать содержимое всего столбца сразу без метода chunking. Независимо от того, насколько это возможно, зависит как от размера свободной памяти, так и от доступной памяти клиента.

var buffer = (byte[])cmd.ExecuteScalar();
fs.Write(buffer, 0, buffer.Length);

Ответ 3

С помощью поставщика .NET SQL Server вы можете использовать малоизвестный, но классный класс SqlBytes. Он был разработан специально для отображения полей varbinary, но примеров его использования не так много.

Вот как вы можете сохранить в базе данных с ним (вы можете использовать хранимую процедуру или прямой SQL, как я здесь демонстрирую, мы просто предполагаем, что MyBlobColumn - это varbinary).

string inputPath = "YourInputFile";
using (var conn = new SqlConnection(YourConnectionString))
{
    conn.Open();
    using (var cmd = conn.CreateCommand())
    {
        // note we define a '@blob' parameter in the SQL text
        cmd.CommandText = "INSERT INTO MyTable (Id, MyBlobColumn) VALUES (1, @blob)";
        using (var inputStream = File.OpenRead(inputPath))
        {
            // open the file and map it to an SqlBytes instance
            // that we use as the parameter value.
            var bytes = new SqlBytes(inputStream);
            cmd.Parameters.AddWithValue("blob", bytes);

            // undercovers, the reader will suck the inputStream out through the SqlBytes parameter
            cmd.ExecuteNonQuery();
        }
    }
}

Чтобы прочитать файл в потоке из базы данных, вот как вы можете это сделать.

string outputPath = "YourOutputFile";
using (var conn = new SqlConnection(YourConnectionString))
{
    conn.Open();
    using (var cmd = conn.CreateCommand())
    {
        // this is a regular direct SQL command, but you can use a stored procedure as well
        cmd.CommandText = "SELECT MyBlobColumn FROM MyTable WHERE Id = 1";

        // note the usage of SequentialAccess to lower memory consumption (read the docs for more)
        using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
        {
            if (reader.Read())
            {
                // again, we map the result to an SqlBytes instance
                var bytes = reader.GetSqlBytes(0); // column ordinal, here 1st column -> 0

                // I use a file stream, but that could be any stream (asp.net, memory, etc.)
                using (var file = File.OpenWrite(outputPath))
                {
                    bytes.Stream.CopyTo(file);
                }
            }
        }
    }
}

С помощью этих методов мы никогда не выделяли ни одного байта [], ни экземпляры MemoryStream, просто используемые в SQL файлах или из них.