How to save a binary file accessed from a database in C#? - c#

I have accessed a database which stores employee photos through a c# query. My question is: how can I save the photos to a regular file on my hard drive through a c# program? To create the file, I understand I will be using FileMode.Create and perhaps the SaveFileDialog class?
This is how I have read in the file:
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(queryString, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
try
{
while (reader.Read())
{
Console.WriteLine(String.Format("{0}, {1}, {2}, {3}", reader["emp_id"], reader["first_name"], reader["last_name"], reader["photo"]));
FileStream fs = new FileStream(SaveFileDialog.FileName, FileMode.Open); //something of this nature?
}
}
finally
{
reader.Close();
}
}
I have extracted necessary information from this SO question, but it doesn't really help me on saving the file. So, I am asking for some assistance on how to go about saving a binary file, which is a picture, that I want to save on my computer.

File.WriteAllBytes will write bytes to a file of a given name.
In full, something like
File.WriteAllBytes(fileName, (byte[])reader["photo"]);
You can use a save file dialog to save the files, yes. But that's really more a question of your UX design (and application design). In general, loops and dialogs don't play very well - if you make me select 10 different file names to save photos with names you could choose yourself, I'm going to be angry at you :P

Related

Deserialize SQL Server image field back in Excel format

I have a SQL Server table that contains serialized Excel files, with 3 fields:
IdDocument -> int (PK)
DataFile -> image
FileName -> nvarchar
where DataFile contains the Excel file serialized, and FileName the name of the file (with path).
Something like this:
0xD0CF11E0A1B11AE100.....
U:\SAP_R3V4_Validation_Documents\March2012.xls
Now I need to get these files back in Excel format.
How can I accomplish this?
Using C# console application or SQL Server features could be fine.
Thank you in advance.
Luis
Excel files are binary. The xls format is obsolete, replaced since 2007 (15 years ago) by xlsx, a ZIP package containing XML files. What the question shows is how binary data looks in SSMS, not some kind of serialized format.
BTW the image is deprecated, replaced by varbinary(max) in 2005 or 2008 (can't remember).
In any case, reading binary data is the same as reading any other data. A DbDataReader is used to retrieve the query results and strongly typed methods are used to read specific fields per row. In this particular case GetStream() can be used to retrieve the data as a Stream that can be saved to disk:
using var con=new SqlConnection(connectionString)
{
using (var cmd=new SqlCommand(sql,con))
{
using (var reader=cmd.ExecuteReader())
{
while(reader.Read())
{
var path=reader.GetString(2);
var finalPath=Path.Combine(root,Path.GetFileName(path))
using(var stream=reader.GetStream(1))
{
using(var fileStream=File.Create(finalPath))
{
stream.CopyTo(fileStream);
}
}
}
}
}
}
The only thing that's different is the code that reads the field as a stream and saves it to disk
using(var stream=reader.GetStream(1))
{
using(var fileStream=File.Create(finalPath))
{
stream.CopyTo(fileStream);
}
}
The using clauses are used to ensure the data and file streams are closed even in case of error. The path itself is constructed by combining a root folder with the stored filename, not the full path

Open Word file stored in SQL Server

We successfully add word documents in our SQL Server (varbinary column) using some web forms, then, we want some of our staff to be able to download them.
We have some code to display it, but sometimes it does display (in my local environment), sometimes it does not, but then, when it goes live to Production. So, we just want to download it, it doesn't matter if it opens or if it does not (in case you don't have Word installed), we just want to have it downloaded, something like the "Save as..." function. Because in my local environment it works well, but when it goes live to a IIS server, we are not able to retrieve the file (I am guessing, it is because it opens WORD automatically).
Here is the code to retrieve it.
public string showDoc(int id, int numRef)
{
string fileName = Path.GetTempFileName() + ".docx";
Db.Open();
string cuerito = "select doc from tbl_references where [userId]=#id and [refNum]=#numRef";
SqlCommand command = new SqlCommand(cuerito, base.Db);
command.Parameters.AddWithValue("#id", id);
command.Parameters.AddWithValue("#numRef", numRef);
using (SqlDataReader dr = command.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;
}
}
}
}
Db.Close();
return fileName;
}
Is there a way in C# just to do this? Not display but only download it from SQL Server?
EB.
All the code above does is read some data from a binary field and write it to a stream, which gets written to the disk on the server. There's no need to save the file to disk before you offer it for download, you can simply stream the data directly to the client - there are tons of examples and previous questions containing working examples of this process if you google it. They will work with any file, none of this is specific to Word files. And none of it relates to interop in any way.
BTW whether the file downloads directly to the user's disk or is opened up (saved in a temp folder on the user's machine) is largely down to the config of the user's machine, which browser they use, whether the Word plugin is installed in that browser, their general download settings. You can set HTTP headers (again google it) which hint to the browser to just save the file instead of trying to open it, but ultimately it's in the control of the browser, not the server.
Here's one reasonably simple example of sending binary data from a database table as a file download: https://ygtechme.wordpress.com/2012/08/27/downloading-file-from-database-using-c-asp-net/. There are dozens more similar ones with slight variations on the theme available online. But this is the general idea.
The code you posted already does what you ask for.

Retrieving Compressed files from database

I have a SQL Server 2008-R2 database that has a table that is storing different types of files (Word Docs, PDF, TIF, etc), I can successfully retrieve these files from the database using the following method:
private void GetFilesFromDatabase() {
try
{
const string connStr = #"Data Source=localhost\SQLInstance;Initial Catalog=MyData;Integrated Security=True;";
//Initialize SQL Server connection.
SqlConnection CN = new SqlConnection(connStr);
//Initialize SQL adapter.
SqlDataAdapter ADAP = new SqlDataAdapter("Select ole_id, ole_object From OLE Where ole_id = 21601", CN);
//Initialize Dataset.
DataSet DS = new DataSet();
//Fill dataset with FilesStore table.
ADAP.Fill(DS, "FilesStore");
//Get File data from dataset row.
byte[] FileData = (byte[])DS.Tables["FilesStore"].Rows[0]["ole_object"];
string FileName = #"C:\Temp\Text.doc";
//Write file data to selected file.
using (FileStream fs = new FileStream(FileName, FileMode.Create))
{
fs.Write(FileData, 0, FileData.Length);
fs.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
This file I am retrieving is a Word Doc file according to other information contained in that particular row. When I attempt to open the file after retrieving it to disk the data all appears to be gibberish and is not able to be read. Now I believe that these files were compressed prior to be saved to the database but I don't know how to de-compress them so that they can be viewed, any thoughts on how I may accomplish this? My ultimate goal is to move these images into another database.
Your code to save files look OK. Assuming your original data was .DOC file and you got bad file after saving you pretty much out of luck. You may want to look at the content of the file in binary editor (i.e. Visual Studio's one) to confirm that file is not something obviously different (text/image....).
You need to ask around how files where stored in the database. There is no way this can be answered remotely as it could be compressed, encrypted, split into chunks or even simply corrupted.

how to get a picture from a postgresql database

i want to select a picture that save as a large object in a postgresql database.
i know i use lo_export to do this.
but there is a problem: i want to save this picture directly to my computer because i cant access the files that save on Server using lo_export
(i think that is best for me if picture transfer to my computer by a select query)
I don't exactly know my way around C# but the Npgsql Manual has an example sort of like this of writing a bytea column to a file:
command = new NpgsqlCommand("select blob from t where id = 1);", conn);
Byte[] result = (Byte[])command.ExecuteScalar();
FileStream fs = new FileStream(args[0] + "database", FileMode.Create, FileAccess.Write);
BinaryWriter bw = new BinaryWriter(new BufferedStream(fs));
bw.Write(result);
bw.Flush();
fs.Close();
bw.Close();
So you just read it out of the database pretty much like any other column and write it to a local file. The example is about half way down the page I linked to, just search for "bytea" and you'll find it.
UPDATE: For large objects, the process appears to be similar but less SQL-ish. The manual (as linked to above) includes a few large object examples:
NpgsqlTransaction t = Polacz.BeginTransaction();
LargeObjectManager lbm = new LargeObjectManager(Polacz);
LargeObject lo = lbm.Open(takeOID(idtowaru),LargeObjectManager.READWRITE); //take picture oid from metod takeOID
byte[] buf = new byte[lo.Size()];
buf = lo.Read(lo.Size());
MemoryStream ms = new MemoryStream();
ms.Write(buf,0,lo.Size());
// ...
Image zdjecie = Image.FromStream(ms);
Search the manual for "large object" and you'll find it.
Not familiar with C# but if you've contrib/dblink around and better access to a separate postgresql server, this might work:
select large object from bad db server.
copy large object into good db server using dblink.
lo_export on good db server.
If your pictures don't exceed 1GB (or if you don't access only parts of the bytes) then using bytea is the better choice to store them.
A lot of SQL GUI tools allow to directly download (even view) the content of bytea columns directly

To store and search word documents using C#.NET,ASP.NET

i want to store a word documents (.doc) in the database and i need to provide search over a collection of Word documents and highlight the words too.
I m using VS2005 --> ASP.NET, C#.NET, SQL Server.
you can store it in DB as a BLOB (Binary Large OBject).
Something similar would work
string filePath = "";
string connectionString = "";
FileStream stream =
new FileStream(filePath, FileMode.Open, FileAccess.Read);
BinaryReader reader = new BinaryReader(stream);
byte[] file = reader.ReadBytes((int)stream.Length);
reader.Close();
stream.Close();
SqlCommand command;
SqlConnection connection = new SqlConnection(connectionString);
command =
new SqlCommand("INSERT INTO FileTable (File) Values(#File)", connection);
command.Parameters.Add("#File", SqlDbType.Binary, file.Length).Value = file;
connection.Open();
command.ExecuteNonQuery();
have a look at this post for bit more
details :
How to store word documents in Database using C#
You can store the documents as BLOBs as described above. You then need some way of indexing the contents so you can search.
You could be crude and extract the contents of the Word document as text, store this along with the document and then query this new column using the keywords.
This is not going to be particuarly quick or efficent though. It looks as though Full-Text Indexing may do the trick: http://www.codeproject.com/KB/architecture/sqlfulltextindexing.aspx
Apparently Office documents can be indexed.
When a keyword is entered you can then query the full-text index, find matching documents and then open the documents and highlight the words using either the Office Primary Interop assesmbiles or VSTO.
Is your site public? A good unconventional solution is to use Google. Type into google:
site:www.yoursite.com filetype:doc searchTerm
Here is an example. Notice the View HTML link hightlights the text.
WhiteHouse.gov OMB Search
If you want to get fancy, you could use the WebRequest object to make the request to Google on the server, and then parse out the response to just display the ViewHtml links on your page.

Categories

Resources