C#: file corrupted after downloading as byte array - c#

I have a project in which I store documents as blobs in a MySQL database, and download them as byte arrays using C#:
public static byte[] GetFile(string fileName)
{
conn.Open();
MySqlCommand cmd = conn.CreateCommand();
cmd.CommandText = ...
using (MySqlDataReader reader = cmd.ExecuteReader())
{
reader.Read();
if (reader.HasRows)
{
return Util.ObjectToByteArray(reader["Content"]);
}
...
}
...
public static byte[] ObjectToByteArray(object obj)
{
BinaryFormatter bf = new BinaryFormatter();
using (var ms = new MemoryStream())
{
bf.Serialize(ms, obj);
return ms.ToArray();
}
}
I upload the files like this:
byte[] newFile = File.ReadAllBytes(fileName);
and download like this:
File.WriteAllBytes(path + "\\" + selectedFileName,
DocumentTable.GetFile(selectedFileName));
but when I download the files, they are corrupted and cannot be opened (for example Excel files, some other types can be opened). The extension of the downloaded file seems to be correct, but I am getting the message that "the file extension or file format are not valid".

I recommend using the GetStream() override of the data reader;
content = reader.GetStream(1);
and simply returning the stream object to your File writer.

Related

Stored exe File in sql is not executable after Loaded From SQL Server

We are trying to store an executable(exe) file in SQL. We are getting no error either writing or reading. Just the file we stored is not working after downloading back.
This is how we store the file:
databaseFilePut(#"FilePath", con, dt.Rows[0].ItemArray[0].ToString(), "ASIL");
And this is the inside of the function:
public static void databaseFilePut(string varFilePath, SqlConnection con, string version, string OFSET )
{
byte[] file;
using (var stream = new FileStream(varFilePath, FileMode.Open, FileAccess.Read))
{
using (var reader = new BinaryReader(stream))
{
file = reader.ReadBytes((int)stream.Length);
}
}
using (var sqlWrite = new SqlCommand("UPDATE ERP_TOOL_UPDATE SET Version=#Version1, ExeDosyasi= #ExeDosyasi1, OFSET= #OFSET1", con))
{
sqlWrite.Parameters.AddWithValue("#Version1", (double.Parse(version) + 1).ToString());
sqlWrite.Parameters.Add("#ExeDosyasi1", SqlDbType.VarBinary, file.Length).Value = file;
sqlWrite.Parameters.AddWithValue("#OFSET1", "ASIL");
sqlWrite.ExecuteNonQuery();
}
}
After saving to the database this is what the data like:
0x4D5A90000300000004000000FFFF0000B8000.... and goes on.
After reading we try to recreate the stored exe with this code:
SqlCommand com = new SqlCommand("Select ExeDosyasi From ERP_TOOL_UPDATE WHERE OFSET = 'ASIL' ", con);
com.CommandType = CommandType.Text;
SqlDataReader reader = com.ExecuteReader();
reader.Read();
byte[] blob;
byte[] blob2;
blob = (byte[])reader[0];
blob2 = System.Text.Encoding.Default.GetBytes(System.Text.Encoding.Unicode.GetString(blob));
using (var fs = new FileStream(#"C:\Users\Bilal\Desktop\ERPAnalizTool.exe", FileMode.Create, FileAccess.Write))
{
fs.Write(blob2, 0, blob2.Length);
fs.Flush();
}
We are not getting any errors, it saves the file. Just the problem is the file has a little bit smaller size. When we try to run, it doesn't run. Like it never was an exe before.
Any help would be appreciated. Thank you all.
Your problem is the following line:
blob2 = System.Text.Encoding.Default.GetBytes(System.Text.Encoding.Unicode.GetString(blob));
The blob variable contains the bytes you wrote to the database, which is the content of the file read in the databaseFilePut method. There is no reason at all to convert it to a Unicode string and then to the system default encoding (Windows-1252 on my system). The data is not a string, it is binary. The double conversion will simply produce a mangled byte sequence.
Simply write the blob variable to disk:
blob = (byte[])reader[0];
File.WriteAllBytes(#"C:\Users\Bilal\Desktop\ERPAnalizTool.exe", blob);

Load a file from Asset using Xamarin android

I want to load a file from the Asset, I found the solution but with Java. How can I convert following Java code to c#.
public String loadKMLFromAsset() {
String kmlData = null;
try {
InputStream is = getAssets().open("yourKMLFile");
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
kmlData = new String(buffer, "UTF-8");
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
return kmlData;
}
Use AssetManager
// Read the contents of our asset
string content;
AssetManager assets = this.Assets;
using (StreamReader sr = new StreamReader (assets.Open ("read_asset.txt")))
{
content = sr.ReadToEnd ();
}
Use BinaryReader instead of streamReader, if u are working with files such as db, kml, shapefiles,, video formats, etc. StreamReader reads only strings or just plain text, so when reading binary file some of the content may be skipped, since streamreader doesnt read byte by byte
This code writes the asset file to a file in your mobile file system:
if (!System.IO.File.Exists("yourKMLFile_mobile"))
{
var s = Resources.OpenRawResource(Resource.Raw.yourKMLFile);
FileStream writeStream = new FileStream("yourKMLFile_mobile", FileMode.OpenOrCreate, FileAccess.Write);
ReadWriteStream(s, writeStream);
}

How to attach files to dotnet zip library c#

I am using dotnet zip library to create zip file. My files are saved into a database and I am reading each row and load file data into memory from the database and save the memory stream to zip file. my below code works fine.
using System.IO;
using Ionic.Zip;
private void button2_Click(object sender, EventArgs e)
{
using (SqlConnection sqlConn = new SqlConnection(#"Data Source=BBATRIDIP\SQLSERVER2008R2;Initial Catalog=test;Integrated Security=True"))
{
string query = String.Format(#"SELECT Name, ContentType, Data FROM [TestTable]");
SqlCommand cmd = new SqlCommand(query, sqlConn);
cmd.Connection.Open();
System.IO.MemoryStream memStream = null;
ZipFile zip = new ZipFile();
zip.MaxOutputSegmentSize = 1024 * 1024; // 1MB each segment size would be
// the above line would split zip file into multiple files and each file
//size would be 1MB
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
byte[] data = (byte[])reader["Data"];
memStream = new System.IO.MemoryStream(data);
string strFile = reader["Name"].ToString() + "\\" + reader["ContentType"].ToString();
ZipEntry ze = zip.AddEntry(strFile, memStream);
int xx = 0;
}
}
zip.Save(#"e:\MyCustomZip.zip");
memStream.Dispose();
MessageBox.Show("Job Done");
// here u can save the zip in memory stream also there is a overload insteaa of saving in HD
}
}
but if i change a bit into the code then corrupted zip file is creating. if i change this line zip.Save(#"e:\MyCustomZip.zip"); then problem occur.
using (SqlConnection sqlConn = new SqlConnection(#"Data Source=BBATRIDIP\SQLSERVER2008R2;Initial Catalog=test;Integrated Security=True"))
{
string query = String.Format(#"SELECT Name, ContentType, Data FROM [TestTable]");
SqlCommand cmd = new SqlCommand(query, sqlConn);
cmd.Connection.Open();
System.IO.MemoryStream memStream = null;
ZipFile zip = new ZipFile();
zip.MaxOutputSegmentSize = 1024 * 1024; // 1MB each segment size would be
// the above line would split zip file into multiple files and each file
//size would be 1MB
zip.Save(#"e:\MyCustomZip.zip");
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
byte[] data = (byte[])reader["Data"];
memStream = new System.IO.MemoryStream(data);
string strFile = reader["Name"].ToString() + "\\" + reader["ContentType"].ToString();
ZipEntry ze = zip.AddEntry(strFile, memStream);
int xx = 0;
}
}
memStream.Dispose();
MessageBox.Show("Job Done");
// here u can save the zip in memory stream also there is a overload insteaa of saving in HD
}
I want to create zip with zero kb initially and when I will add stream to zip in loop then zip file size will increase gradually. if you see my above code where I try to do that but I got no success. what am I doing wrong in the code?
Another issue
dotnet zip compression ratio not good. i zip a 152 KB doc file with dotnet zip and when zip was created then i was zip file size was 136KB. is there any tweak exist which create small size zip file. share the knowledge. thanks
So, looking at the documentation for ZipFile.Save, we see the following:
Use this when creating a new zip file, or when updating a zip archive.
So, it seems that you need to call this repeatedly to get the "update" behaviour you are looking for. As such just need to move your Save into the loop:
//...
ZipFile zip = new ZipFile();
zip.MaxOutputSegmentSize = 1024 * 1024;
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
byte[] data = (byte[])reader["Data"];
memStream = new System.IO.MemoryStream(data);
string strFile =
reader["Name"].ToString() + "\\" + reader["ContentType"].ToString();
ZipEntry ze = zip.AddEntry(strFile, memStream);
zip.Save(#"e:\MyCustomZip.zip");
}
}
With regards to your second question (never a good idea on SO, try to stick to one problem per question):
Without knowing what you are compressing, it's very difficult to speculate about what kind of compression ratio you might achieve. If the data is already compressed (e.g. compressed image/video such as jpeg/h264), zipping isn't going to give you any gains whatsoever. Your only hint about the nature of the content is that it is a "doc". If you're talking about a modern Word document (docx), this is already a zip compressed folder structure. Gains will be minimal. If it's another kind of doc, perhaps it contains embedded (compressed) media? This will also be relatively incompressible.

C# Binary Reader

I'm making an encryption program and need to save the encrypted password to a file using the binary reader and writer. When i try and read the data out all I get is a number. What did I do wrong?
public static string readData(string fileName)
{
string data;
FileStream fStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
using (BinaryReader reader = new BinaryReader(fStream))
{
data = reader.Read().ToString();
}
return data;
}
And the writer
public static void writeData(string fileName, string data)
{
using (BinaryWriter writer = new BinaryWriter(File.Open (fileName, FileMode.Create)))
{
writer.Write(data);
}
}
Use reader.ReadString() instead.
data = reader.ReadString();
The Read method reads the next character and returns the corresponding integer value of it as you can see in the documentation.basically, you have written a string to your file in binary format, so you need to read it back.
That is because you are calling the Read method that returns a single integer.ยจ
You want to do ReadString.

C# Asp.Net Create text file, zip it, and save to Blob - Without writing anything to disk

A complicated one here, well for me anyway :)
Basically what i would like to achieve is to generate some text, zip this text file within two directories and then upload it to a MySQL blob field - all without writing anything to the disk. I am relatively new to all this so any pointers are greatly appreciated. Heres what i have sort of put together so far, it obviously crashes and burns but hopefully gives a better idea of what id like to do. Oh and im using DotNetZip currently :)
public void broadcastItem()
{
System.IO.MemoryStream ms = new System.IO.MemoryStream();
System.IO.StreamWriter sw = new System.IO.StreamWriter(ms);
System.IO.MemoryStream ms2 = new System.IO.MemoryStream();
sw.Write("Some Text generated and placed in a file");
sw.Close(); //Text File Now Created
using (ZipFile zip = new ZipFile())
{
zip.AddDirectory(#"Directory1\Directory2");
//Zipping within two directories
ZipEntry e = zip.AddEntry("Test", ms);
e.
e.Comment = "The content for entry in the zip file was obtained from a stream";
zip.Comment = "This zip was created at " + System.DateTime.Now.ToString("G");
zip.Save(ms2); //Trying to save to memory stream
}
try
{
OdbcConnection Server = new OdbcConnection("DSN=CentralServer");
Server.Open();
OdbcCommand DbCommand = Server.CreateCommand();
DbCommand.CommandText = "INSERT INTO blobtest(blobfield) VALUES(?)";
OdbcParameter param = new OdbcParameter("#file", SqlDbType.Binary);
param.Value = ms2;
DbCommand.Parameters.Add(param);
DbCommand.ExecuteNonQuery();
//Trying to save zip file from memory stream to blob field
}
catch (Exception ex)
{
throw ex;
}
}
** EDIT - Moving Closer ***
I now can create a text file and zip it in memory, problem is the text doesnt display in the file - ie its blank i now have the file within two directories :)
amended code below
public void test3()
{
MemoryStream ms = new MemoryStream();
StreamWriter sw = new StreamWriter(ms);
sw.WriteLine("HELLO!");
sw.WriteLine("I WANT TO SAVE THIS FILE AS A .TXT FILE WITHIN TWO FOLDERS");
ms.Position = 0;
// create the ZipEntry archive from the xml doc store in memory stream ms
MemoryStream outputMS = new System.IO.MemoryStream();
ZipOutputStream zipOutput = new ZipOutputStream(outputMS);
ZipEntry ze = new ZipEntry(#"Directory1\Directory2\example.txt");
zipOutput.PutNextEntry(ze);
zipOutput.Write(ms.ToArray(), 0, Convert.ToInt32(ms.Length));
zipOutput.Finish();
zipOutput.Close();
byte[] byteArrayOut = outputMS.ToArray();
outputMS.Close();
ms.Close();
try
{
OdbcConnection rstServer = new OdbcConnection("DSN=CentralServer");
Server.Open();
OdbcCommand DbCommand = Server.CreateCommand();
DbCommand.CommandText = "INSERT INTO blobtest(blobfield) VALUES(?)";
OdbcParameter param = new OdbcParameter("#file", SqlDbType.Binary);
param.Value = byteArrayOut;
DbCommand.Parameters.Add(param);
DbCommand.ExecuteNonQuery();
Response.Write(byteArrayOut.ToString());
}
catch (Exception ex)
{
Response.Write(ex.ToString());
}
}
You can use the open source c# compression library SharpZipLib to create an in-memory zip file, as explained here: In Memory compression using SharpZipLib
// zip XElement xdoc and add to requests MTOM value
using (MemoryStream ms = new System.IO.MemoryStream())
{
xdoc.Save(ms);
ms.Position = 0;
// create the ZipEntry archive from the xml doc store in memory stream ms
using (MemoryStream outputMS = new System.IO.MemoryStream())
{
using (ZipOutputStream zipOutput = new ZipOutputStream(outputMS))
{
ZipEntry ze = new ZipEntry("example.xml");
zipOutput.PutNextEntry(ze);
zipOutput.Write(ms.ToArray(), 0, Convert.ToInt32(ms.Length));
zipOutput.Finish();
zipOutput.Close();
// add the zip archive to the request
SubmissionReceiptListAttachmentMTOM = new base64Binary();
SubmissionReceiptListAttachmentMTOM.Value = outputMS.ToArray();
}
outputMS.Close();
}
ms.Close();
}
Now you just need to convert the memory stream to a byte array and save it in the database.
Basically this is the whole compilation of what i wanted to achieve so i thought id put this together for anyone who needed something similar down the line - this is a working piece of code
public void diskLess()
{
MemoryStream ms = new MemoryStream();
StreamWriter sw = new StreamWriter(ms);
sw.WriteLine("HELLO!");
sw.WriteLine("I WANT TO SAVE THIS FILE AS A .TXT FILE WITHIN TWO FOLDERS");
sw.Flush(); //This is required or you get a blank text file :)
ms.Position = 0;
// create the ZipEntry archive from the txt file in memory stream ms
MemoryStream outputMS = new System.IO.MemoryStream();
ZipOutputStream zipOutput = new ZipOutputStream(outputMS);
ZipEntry ze = new ZipEntry(#"dir1\dir2\whatever.txt");
zipOutput.PutNextEntry(ze);
zipOutput.Write(ms.ToArray(), 0, Convert.ToInt32(ms.Length));
zipOutput.Finish();
zipOutput.Close();
byte[] byteArrayOut = outputMS.ToArray();
outputMS.Close();
ms.Close();
try
{
OdbcConnection rstServer = new OdbcConnection("DSN=CentralServer");
Server.Open();
OdbcCommand DbCommand = Server.CreateCommand();
DbCommand.CommandText = "INSERT INTO blobtest(blobfield) VALUES(?)";
OdbcParameter param = new OdbcParameter("#file", SqlDbType.Binary);
param.Value = byteArrayOut;
DbCommand.Parameters.Add(param);
DbCommand.ExecuteNonQuery();
Response.Write(byteArrayOut.ToString());
}
catch (Exception ex)
{
Response.Write(ex.ToString());
}
}

Categories

Resources