I'm trying to put a document from my computer into a BLOB column in a MySQL database.
I have tried converting the .doc file into a byte[] array, but it keeps saving [BLOB - 13 B] (which is system.byte[] as a string) to the database instead of the actual bytes.
I don't know which part fails, i have tried multiple converting methods and stuck with this one since:
int curr = 0;
foreach (string path in documenteFinal)
{
try
{
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
using (BinaryReader br = new BinaryReader(fs))
{
byte[] fileData = br.ReadBytes((int)fs.Length);
connection.Open();
MySqlCommand cmd = connection.CreateCommand();
cmd.CommandText = "insert into documents values(null, '" + documenteFinal[curr] + "', '" + fileData + "')";
cmd.ExecuteNonQuery();
connection.Close();
}
}
catch (System.ArgumentNullException)
{ break; }
curr++;
}
That's because you need to tell your query that it is writing to a Blob Field and you're not just trying to store the ToString() representation of fileData.
I haven't tested it, but you should be able to achieve what you are trying to do using parameterized queries:
int curr = 0;
foreach (string path in documenteFinal)
{
var fileBytes = File.ReadAllBytes(path);
connection.Open();
using (var command = new MySqlCommand(
"INSERT INTO documents VALUES(null,'" + documenteFinal[curr] + "',#File)", connection))
{
command.Parameters.Add("#File", MySqlDbType.VarBinary, fileBytes.Length).Value = fileBytes;
command.ExecuteNonQuery();
}
connection.Close();
curr++;
}
You should have add a 0x before binary data and remove the single quotes, try this line in place of yours:
cmd.CommandText = "insert into documents values(null, '" + documenteFinal[curr] + "', 0x" + fileData + ")";
I suggest however to try this more compact source code that makes use of the mysql native LOAD_FILE function:
foreach (string path in documenteFinal) {
try {
connection.Open();
MySqlCommand cmd = connection.CreateCommand();
cmd.CommandText = $"insert into documents values(null, '{path}', LOAD_FILE('{path}'))";
cmd.ExecuteNonQuery();
connection.Close();
} catch(Exception) { break; }
}
Related
For some reason my code fails when I try to update the image for a user. The image is not saved properly. For instance an image of 38 kib is saved as 13 bytes in the database.
This is my code:
public void UploadImage(Image img)
{
OpenConnection();
MySqlCommand command = new MySqlCommand("", conn);
command.CommandText = "UPDATE User SET UserImage = '#UserImage' WHERE UserID = '" + UserID.globalUserID + "';";
byte[] data = imageToByte(img);
MySqlParameter blob = new MySqlParameter("#UserImage", MySqlDbType.Blob, data.Length);
blob.Value = data;
command.Parameters.Add(blob);
command.ExecuteNonQuery();
CloseConnection();
}
public byte[] imageToByte(Image img)
{
using (var ms = new MemoryStream())
{
img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
return ms.ToArray();
}
}
OpenConnection and closeconnection are simply conn.Open() and conn.Close().
The conversion however doesn't fail:
But in the database I see this:
Does anyone have any idea what is going on here?
Replace this code:
OpenConnection();
MySqlCommand command = new MySqlCommand("", conn);
command.CommandText = "UPDATE User SET UserImage = '#UserImage' WHERE UserID = '" + UserID.globalUserID + "';";
byte[] data = imageToByte(img);
MySqlParameter blob = new MySqlParameter("#UserImage", MySqlDbType.Blob, data.Length);
blob.Value = data;
command.Parameters.Add(blob);
command.ExecuteNonQuery();
CloseConnection();
With
var userImage = imageToByte(img);
OpenConnection();
var command = new MySqlCommand("", conn);
command.CommandText = "UPDATE User SET UserImage = #userImage WHERE UserID = #userId;";
var paramUserImage = new MySqlParameter("#userImage", MySqlDbType.Blob, userImage.Length);
var paramUserId = new MySqlParameter("#userId", MySqlDbType.VarChar, 256);
paramUserImage.Value = userImage;
paramUserId.Value = UserID.globalUserID;
command.Parameters.Add(paramUserImage);
command.Parameters.Add(paramUserId);
command.ExecuteNonQuery();
CloseConnection();
You were sending '#UserImage' which is a 10 byte long string, remove the quotes and it should work.
Above code also uses parameters for both of your variables which you should always do.
Either way hope this helps you.
At first, i like to save blobs in the database good one :)
If you pass a parameter, do not encapsulate it in ', because than ADO.Net/MySql will not recognize it as a parameter, rather than a string:
command.CommandText = "UPDATE User SET UserImage = #UserImage WHERE UserID = '" + UserID.globalUserID + "';";
If you start using parameter, why not pass UserID also as a parameter:
command.CommandText = "UPDATE User SET UserImage = #UserImage WHERE UserID = #userId;";
This would make every think much clearer.
One important thing: If you store blobs in the database, never use select * from ..., because often you don't want to retrieve the blob, but you will with the star. This cause unnecessary trafic and decrease the performance.
Hope this helps!
Following is the code to upload file in party_images table.
protected void upload_Click(object sender, EventArgs e)
{
try
{
using (OracleConnection connection = new OracleConnection(conString))
{
connection.Open();
string filename = Path.GetFileName(FileUpload1.FileName);
string[] tokenize = filename.Split('.');
FileUpload1.SaveAs(Server.MapPath("~/files/") + descBox.Text + "." + tokenize[1]);
string sourceLoc = Server.MapPath("~/files/" + descBox.Text + "." + tokenize[1]);
FileStream fs = new FileStream(sourceLoc, FileMode.Open, FileAccess.Read);
byte[] ImageData = new byte[fs.Length];
fs.Read(ImageData, 0, System.Convert.ToInt32(fs.Length));
fs.Close();
String block = " BEGIN " +
" INSERT INTO party_images(party_id, sr_no, descr, party_image) VALUES ('"+Session["userId"]+"',"+srNo.Text+",'"+descBox.Text+"."+tokenize[1]+"', :1); " +
" END; ";
OracleCommand cmd = new OracleCommand();
cmd.CommandText = block;
cmd.Connection = connection;
cmd.CommandType = CommandType.Text;
OracleParameter param = cmd.Parameters.Add("blobtodb", OracleDbType.LongRaw);
param.Direction = ParameterDirection.Input;
param.Value = ImageData;
cmd.ExecuteNonQuery();
descBox.Text = "";
srNo.Text = "";
}
}
catch (Exception ex) {
ClientScript.RegisterStartupScript(this.GetType(), "unSuccessMessage", "window.onload = function(){ alert('"+ex.Message+"')};", true);
}
finally
{
populateGrid(loadFromDb());
}
}
table description is,
PARTY_ID is VARCHAR2(10)
SR_NO is NUMBER
DESCR is VARCHAR2(50)
PARTY_IMAGE is LONG RAW()
This function is uploading all the files i.e., images,.docx,.pdf,.sql but when I upload any .docx containing screen shots or pictures then the upper error appears.
I have tried the following links,
ORA-01460: unimplemented or unreasonable conversion requested
The requested format conversion is not supported.
ORA-01460: unimplemented or unreasonable conversion requested
But I haven't got any solution. How can I upload any type of file without having this error?
Why are you using LONG RAW to store binary objects? That's a datatype which has been deprecated for over twenty years.
If you define PARTY_IMAGE as a BLOB (or maybe BFILE) you will find it a lot easier to work with. Find out more.
For some reason my code fails when I try to update the image for a user. The image is not saved properly. For instance an image of 38 kib is saved as 13 bytes in the database.
This is my code:
public void UploadImage(Image img)
{
OpenConnection();
MySqlCommand command = new MySqlCommand("", conn);
command.CommandText = "UPDATE User SET UserImage = '#UserImage' WHERE UserID = '" + UserID.globalUserID + "';";
byte[] data = imageToByte(img);
MySqlParameter blob = new MySqlParameter("#UserImage", MySqlDbType.Blob, data.Length);
blob.Value = data;
command.Parameters.Add(blob);
command.ExecuteNonQuery();
CloseConnection();
}
public byte[] imageToByte(Image img)
{
using (var ms = new MemoryStream())
{
img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
return ms.ToArray();
}
}
OpenConnection and closeconnection are simply conn.Open() and conn.Close().
The conversion however doesn't fail:
But in the database I see this:
Does anyone have any idea what is going on here?
Replace this code:
OpenConnection();
MySqlCommand command = new MySqlCommand("", conn);
command.CommandText = "UPDATE User SET UserImage = '#UserImage' WHERE UserID = '" + UserID.globalUserID + "';";
byte[] data = imageToByte(img);
MySqlParameter blob = new MySqlParameter("#UserImage", MySqlDbType.Blob, data.Length);
blob.Value = data;
command.Parameters.Add(blob);
command.ExecuteNonQuery();
CloseConnection();
With
var userImage = imageToByte(img);
OpenConnection();
var command = new MySqlCommand("", conn);
command.CommandText = "UPDATE User SET UserImage = #userImage WHERE UserID = #userId;";
var paramUserImage = new MySqlParameter("#userImage", MySqlDbType.Blob, userImage.Length);
var paramUserId = new MySqlParameter("#userId", MySqlDbType.VarChar, 256);
paramUserImage.Value = userImage;
paramUserId.Value = UserID.globalUserID;
command.Parameters.Add(paramUserImage);
command.Parameters.Add(paramUserId);
command.ExecuteNonQuery();
CloseConnection();
You were sending '#UserImage' which is a 10 byte long string, remove the quotes and it should work.
Above code also uses parameters for both of your variables which you should always do.
Either way hope this helps you.
At first, i like to save blobs in the database good one :)
If you pass a parameter, do not encapsulate it in ', because than ADO.Net/MySql will not recognize it as a parameter, rather than a string:
command.CommandText = "UPDATE User SET UserImage = #UserImage WHERE UserID = '" + UserID.globalUserID + "';";
If you start using parameter, why not pass UserID also as a parameter:
command.CommandText = "UPDATE User SET UserImage = #UserImage WHERE UserID = #userId;";
This would make every think much clearer.
One important thing: If you store blobs in the database, never use select * from ..., because often you don't want to retrieve the blob, but you will with the star. This cause unnecessary trafic and decrease the performance.
Hope this helps!
I am having some trouble with my update() method. The idea is that the user Provides a recipe name, ingredients, instructions and then selects an image using Filestream.
Once the user clicks 'Add Recipe' this will call the update method, however as things stand I am getting an error which is mentioning the contents of the text box:
Here is the update() method code:
private void updatedata()
{
// filesteam object to read the image
// full length of image to a byte array
try
{
// try to see if the image has a valid path
if (imagename != "")
{
FileStream fs;
fs = new FileStream(#imagename, FileMode.Open, FileAccess.Read);
// a byte array to read the image
byte[] picbyte = new byte[fs.Length];
fs.Read(picbyte, 0, System.Convert.ToInt32(fs.Length));
fs.Close();
//open the database using odp.net and insert the lines
string connstr = #"Server=mypcname\SQLEXPRESS;Database=RecipeOrganiser;Trusted_Connection=True";
SqlConnection conn = new SqlConnection(connstr);
conn.Open();
string query;
query = "insert into Recipes(RecipeName,RecipeImage,RecipeIngredients,RecipeInstructions) values (" + textBox1.Text + "," + " #pic" + "," + textBox2.Text + "," + textBox3.Text + ")";
SqlParameter picparameter = new SqlParameter();
picparameter.SqlDbType = SqlDbType.Image;
picparameter.ParameterName = "pic";
picparameter.Value = picbyte;
SqlCommand cmd = new SqlCommand(query, conn);
cmd.Parameters.Add(picparameter);
cmd.ExecuteNonQuery();
MessageBox.Show("Image successfully saved");
cmd.Dispose();
conn.Close();
conn.Dispose();
Connection();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Can anyone see where I have gone wrong with the insert into Recipes query or suggest an alternative approach to this part of the code?
Your code is open to SQL Injection, but probably your error comes from some text that contains a single quote (the instructions fields for example) and this break your command string build using concatenating the user input.
EDIT
As someone pointed in comment the error is caused by the missing quotes around your textboxes. But while easy to fix that's not the way to go because it is wrong to fix the error adding the missing quotes. It is just postponig the problem leaving a big security hole waiting to be exploited.
A parameterized query could avoid all this mess.
string connstr = "....";
string query = "insert into Recipes(RecipeName,RecipeImage,RecipeIngredients,RecipeInstructions) " +
"values (#name, #pic, #ing, #instr)";
using(SqlConnection conn = new SqlConnection(connstr))
using(SqlCommand cmd = new SqlCommand(query, conn))
{
conn.Open();
SqlParameter picparameter = new SqlParameter();
picparameter.SqlDbType = SqlDbType.Image;
picparameter.ParameterName = "#pic";
picparameter.Value = picbyte;
cmd.Parameters.Add(picparameter);
cmd.Parameters.AddWithValue("#name", textbox1.Text);
cmd.Parameters.AddWithValue("#ing", textbox2.Text);
cmd.Parameters.AddWithValue("#instr", textbox3.Text);
cmd.ExecuteNonQuery();
MessageBox.Show("Image successfully saved");
}
Since you using string concatenations, you probably missed a quote or you put an extra quote or missed a comma or put extra comma etc etc....
Don't use this way!
Your error doesn't look obviously but you should always use parameterized queries. This kind of string concatenations are open for SQL Injection attacks.
query = "insert into Recipes(RecipeName,RecipeImage,RecipeIngredients,RecipeInstructions) values (#p1, #pic, #p3, #p4)";
SqlCommand cmd = new SqlCommand(query, conn);
cmd.Parameters.AddWithValue(#p1, textBox1.Text);
cmd.Parameters.AddWithValue(#pic, textBox1.Text);
cmd.Parameters.AddWithValue(#p3, textBox1.Text);
cmd.Parameters.AddWithValue(#p4, picparameter);
try this
query = "insert into Recipes(RecipeName,RecipeImage,RecipeIngredients,RecipeInstructions) values ('" + textBox1.Text + "'," + " #pic" + ",'" + textBox2.Text + "','" + textBox3.Text + "')";
I use the Microsoft.ACE.OLEDB.12.0 driver in my C# to read and write to excel files (XLS).
The extended properties for my reader looks like : Excel 8.0;HDR=NO;IMEX=1;
and for writer looks like : Excel 8.0;HDR=NO;IMEX=0;
This is the scenario :
I read from an excel file, say input.xls , and create a new output.xls file and write to it using my writer.
Now I open the file output.xls in MS Excel, and add a few more rows to it.
Next, I feed my output.xls as input to my program, and when I debug, I see that it reads only the rows originally written using OleDb. It does not read any of the new rows I added and the writer spits out the rows that were read.
Is this how OleDb works? i.e. treat the database as locked by it, and doesn't value external inserts.
Or could there be an issue with how I create and save the files?
private void Initialize(string fileName, FileType fileType)
{
string connectionString = GetConnectionString(fileName, fileType);
string sheet;
using (OleDbConnection connection = OpenConnection(connectionString))
{
DataTable sheets = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
}
tableName = "[ListingDetails]";
conn = new OleDbConnection();
conn.ConnectionString = connectionString;
conn.Open();
cmd1 = new OleDbCommand();
cmd1.Connection = conn;
cmd1.CommandText = string.Format(CultureInfo.InvariantCulture, #"CREATE TABLE {0} {1}", tableName, fieldstring);
int x = cmd1.ExecuteNonQuery();
}
public void InsertRow(string[] data)
{
StringBuilder fieldString = new StringBuilder();
fieldString.Append("(");
foreach (var h in headers)
{
fieldString.Append(" ["+h+"], ");
}
fieldString.Remove(fieldString.Length - 2, 2);
fieldString.Append(")");
StringBuilder dataString = new StringBuilder();
dataString.Append("('");
foreach (var d in data)
{
if(d!=null)
dataString.Append(d.Replace("'", "''") + "', '");
else
dataString.Append("', '");
}
dataString.Remove(dataString.Length - 4, 4);
dataString.Append("')");
cmd1.CommandText = string.Format(CultureInfo.InvariantCulture, #"INSERT INTO {0} {1} values {2}", tableName, fieldString, dataString);
int x = cmd1.ExecuteNonQuery();
}
For closing the file, I just do a conn.Close();
I'm somehow suspecting the way I'm creating/using the sheet here in the Initialize() method.
P.S. I've seen a similar question, but the issue there seemed to be something with the Data and IMEX flag not being set to 1. Let me tell you before hand that this is not a duplicate question.
Thanks
I used the code below, which is really a simplification of your code but with a few minor changes. It works everytime and I can even have Excel open and watch the rows being inserted as I execute the code. I can then make edits to the file and subsequently load them into a datagrid while the file is still open and without ever having saved the changes.
private void Initialize(string fileName, string tableName)
{
string connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + fileName + ";Mode=ReadWrite;Extended Properties=\"Excel 8.0;HDR=NO\"";
string fieldstring = "(ID int, Field1 char(255), Field2 char(255))";
using (OleDbConnection conn = new OleDbConnection(connectionString))
{
conn.Open();
using (OleDbCommand cmd = new OleDbCommand())
{
cmd.Connection = conn;
cmd.CommandText = string.Format(CultureInfo.InvariantCulture, #"CREATE TABLE [{0}] {1}", tableName, fieldstring);
cmd.ExecuteNonQuery();
}
conn.Close();
}
}
public void InsertRow(string fileName, string tableName, string data)
{
string connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + fileName + ";Mode=ReadWrite;Extended Properties=\"Excel 8.0;HDR=YES\"";
string headers = "ID,Field1,Field2";
using (OleDbConnection conn = new OleDbConnection(connectionString))
{
conn.Open();
using (OleDbCommand cmd = new OleDbCommand())
{
cmd.Connection = conn;
cmd.CommandText = string.Format(CultureInfo.InvariantCulture, #"INSERT INTO [{0}$] ({1}) values({2})", tableName, headers, data);
txtQuery.Text = cmd.CommandText;
cmd.ExecuteNonQuery();
}
conn.Close();
}
}
Create the file with
Initialize("C:\\path\\to\\file\\Test File.xls", "ListingDetails");
Insert test rows with
for (int i = 0; i < 10; i++)
{
InsertRow("C:\\path\\to\\file\\Test File.xls", "ListingDetails",
"'" + i.ToString() + "','test" + (i + 2).ToString() + "','test" + (i + 5).ToString() + "'");
}
I cleaned up the code surrounding the creation and disposal of the OleDb objects. This may have been causing problems for you, I'm not sure, but this way at least you know that everything is getting finished off properly.
Hope this helps.