Reading SQL Varbinary Blob from Database

后端 未结 3 1240
情书的邮戳
情书的邮戳 2021-01-01 18:12

I am working on saving files to sql blob to a varbinary(max) column, and have got the save side of things working now (I believe).

What I can\'t figure out is how to

3条回答
  •  陌清茗
    陌清茗 (楼主)
    2021-01-01 18:32

    You are making it more difficult than it needs to be. This is using MySQL just because it is handy - the providers all work pretty much the same. Some things will need to be tweaked to handle very large data items (more of a server thing than DB Provider).

    Saving image

    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();
    }
    

    The file data is fed directly to the DB Provider

    is there a way to get the full path including file extension of a file stored in an SQL Blob?

    No. Your code and the code above is saving the bytes which make up an image or any file.

    Read Img Data back

    This will read the data back, save it to file and start the associated app:

    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 The number of bytes read back matched
    • 1 The associated app launched just fine with the image
    • 1 The image showed in the picturebox

    In both cases, File.ReadAllBytes() and File.WriteAllBytes() will do most of the work for you, no matter the file type.

    There is no need to scoop out the data 1k at a time. If the blob was something like an image you wished to use in the app:

    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);
            }
        }
    }
    

    The blob bytes can be fed to the memstream, and even a temp Image need not be created unless you don't need to show it.

    In all, Ceiling Cat made it back just fine (image was 1.4 MB, zoomed; another test with a 15.4 MB image also worked - both are larger than I would care to store in a DB).:

    Depending on how this is used, consider archiving the images to somewhere on the file system and just saving the filename - perhaps with the Id added to assure the names are unique and help visually link them to the record. Not only will large blobs of data bloat the DB, but there is obviously some overhead involved in converting to and from bytes which can be avoided.


    If you want/need to delete these at some point after the associated app is done with them (not really a component of the question), then use a tempfile in a specific directory so you can delete everything in it (conditionally1) when the app ends, or at start up:

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

    Append a Temp Filename and the actual extension for individual files. Alternatively, you could maintain a List trashCan to store the name of each file you create to be deleted later.

    1 Whenever you do delete them, do allow that files could still be open in the app associated with the extension.

提交回复
热议问题