I'm trying to convert a .db file to binary so I can stream it across a web server. I'm pretty new to C#. I've gotten as far as looking at code snippets online but I'm not really sure if the code below puts me on the right track. How I can write the data once I read it? Does BinaryReader automatically open up and read the entire file so I can then just write it out in binary format?
class Program
{
static void Main(string[] args)
{
using (FileStream fs = new FileStream("output.bin", FileMode.Create))
{
using (BinaryWriter bw = new BinaryWriter(fs))
{
long totalBytes = new System.IO.FileInfo("input.db").Length;
byte[] buffer = null;
BinaryReader binReader = new BinaryReader(File.Open("input.db", FileMode.Open));
}
}
}
}
Edit: Code to stream the database:
[WebGet(UriTemplate = "GetDatabase/{databaseName}")]
public Stream GetDatabase(string databaseName)
{
string fileName = "\\\\computer\\" + databaseName + ".db";
if (File.Exists(fileName))
{
FileStream stream = File.OpenRead(fileName);
if (WebOperationContext.Current != null)
{
WebOperationContext.Current.OutgoingResponse.ContentType = "binary/.bin";
}
return stream;
}
return null;
}
When I call my server, I get nothing back. When I use this same type of method for a content-type of image/.png, it works fine.
All the code you posted will actually do is copy the file input.db to the file output.bin. You could accomplish the same using File.Copy.
BinaryReader will just read in all of the bytes of the file. It is a suitable start to streaming the bytes to an output stream that expects binary data.
Once you have the bytes corresponding to your file, you can write them to the web server's response like this:
using (BinaryReader binReader = new BinaryReader(File.Open("input.db",
FileMode.Open)))
{
byte[] bytes = binReader.ReadBytes(int.MaxValue); // See note below
Response.BinaryWrite(bytes);
Response.Flush();
Response.Close();
Response.End();
}
Note: The code binReader.ReadBytes(int.MaxValue) is for demonstrating the concept only. Don't use it in production code as loading a large file can quickly lead to an OutOfMemoryException. Instead, you should read in the file in chunks, writing to the response stream in chunks.
See this answer for guidance on how to do that
https://stackoverflow.com/a/8613300/141172
Related
I am trying to make a httplistener server in c# that sends files to the client (who is on a browser). This is my code:
static void SendFile(HttpListenerResponse response, string FileName, string ContentType) {
response.ContentType = ContentType;
// Read contents of file
var reader = new StreamReader(FileName);
var contents = reader.ReadToEnd();
reader.Close();
// Write to output stream
var writer = new StreamWriter(output);
writer.Write(contents);
// Wrap up.
writer.Close();
stream.Close();
response.Close();
}
Unfortunately, this code cannot send binary files, such as images, PDFs, and lots of other file types. How can I make this SendFile function binary-safe?
Thank you for all the comments and the gist link! The solution where you read from the file as a byte[] and write those bytes to the output stream I looked up worked, but is was kind of confusing, so I made a really short SendFile function.
static void SendFile(HttpListenerResponse response, string FileName, string ContentType) {
response.AddHeader("Content-Type", ContentType);
var output = response.OutputStream;
// Open the file
var file = new FileStream(FileName, FileMode.Open, FileAccess.Read);
// Write to output stream
file.CopyTo(output);
// Wrap up.
file.Close();
stream.Close();
response.Close();
}
This code just copies the file to the output stream.
I have a wcf service as following:
public class DocumentReadService : IDocumentReader
{
public Stream GetDocument(string docName)
{
//read file
if (WebOperationContext.Current != null)
{
WebOperationContext.Current.OutgoingResponse.ContentType = "application/pdf";
}
//return file stream
}
}
But when I do unit test(using moq) the above method, I don't get expected stream which is a pdf if saved to a file.
Meaning the pdf should be same as that of what I get when I browse the same wcf service hosted url.
Could anybody give me some advice about this issue?
I got it working, Issue was with the way stream was saved to file in unit test. It should be done with BinaryWriter as following and not as normal stream save to file,
Stream serviceResult = documentReaderMock.GetDocument("abc");
using (FileStream fileStream = File.Create(_sourceFilePath + "\\DownloadedFile.pdf",(int)serviceResult.Length))
{
BinaryWriter bw = new BinaryWriter(fileStream);
byte[] bytesInStream = new byte[serviceResult.Length];
serviceResult.Read(bytesInStream, 0, bytesInStream.Length);
bw.Write(bytesInStream);
bw.Close();
}
I have a file with size 10124, I am adding a byte array, which has length 4 in the beginning of the file.
After that the file size should become 10128, but as I write it to file, the size decreased to 22 bytes. I don't know where is the problem
public void AppendAllBytes(string path, byte[] bytes)
{
var encryptedFile = new FileStream(path, FileMode.Open, FileAccess.Read);
////argument-checking here.
Stream header = new MemoryStream(bytes);
var result = new MemoryStream();
header.CopyTo(result);
encryptedFile.CopyTo(result);
using (var writer = new StreamWriter(#"C:\\Users\\life.monkey\\Desktop\\B\\New folder (2)\\aaaaaaaaaaaaaaaaaaaaaaaaaaa.docx.aef"))
{
writer.Write(result);
}
}
How can I write bytes to the file?
The issue seems to be caused by:
using a StreamWriter to write binary formatted data. The name does not inthuitively suggest this, but the StreamWriter class is suited for writing textual data.
passing an entire stream instead of the actual binary data. To obtain the bytes stored in a MemoryStream, use its convenient ToArray() method.
I suggest you the following code:
public void AppendAllBytes(string path, byte[] bytes)
{
var fileName = #"C:\\Users\\life.monkey\\Desktop\\B\\New folder (2)\\aaaaaaaaaaaaaaaaaaaaaaaaaaa.docx.aef";
using (var encryptedFile = new FileStream(path, FileMode.Open, FileAccess.Read))
using (var writer = new BinaryWriter(File.Open(fileName, FileMode.Append)))
using (var result = new MemoryStream())
{
encryptedFile.CopyTo(result);
result.Flush(); // ensure header is entirely written.
// write header directly, no need to put it in a memory stream
writer.Write(bytes);
writer.Flush(); // ensure the header is written to the result stream.
writer.Write(result.ToArray());
writer.Flush(); // ensure the encryptdFile is written to the result stream.
}
}
The code above uses the BinaryWriter class which is better suited for binary data. It has a Write(byte[] bytes) method overload that is used above to write an entire array to the file. The code uses regular calls to the Flush() method that some may consider not needed, but these guarantee in general, that all the data written prior the call of the Flush() method is persisted within the stream.
Just started with writing unit tests and I am now, blocked with this situation:
I have a method which has a FileStream object and I am trying to pass a "string" to it.
So, I would like to convert my string to FileStream and I am doing this:
File.WriteAllText(string.Concat(Environment.ExpandEnvironmentVariables("%temp%"),
#"/test.txt"), testFileContent); //writes my string to a temp file!
new FileStream(string.Concat(Environment.ExpandEnvironmentVariables("%temp%"),
#"/test.txt"), FileMode.Open) //open that temp file and uses it as a fileStream!
close the file then!
But, I guess there must be some very simple alternative to convert a string to a fileStream.
Suggestions are welcome! [Note there are other answers to this question in stackoverflow but none seems to be a straight forward solution to that]
Thanks in advance!
First of all change your method to allow Stream instead of FileStream. FileStream is an implementation which, as I remember, does not add any methods or properties, just implement abstract class Stream. And then using below code you can convert string to Stream:
public Stream GenerateStreamFromString(string s)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
As FileStream class provides a stream for a file and hence it's constructor requires the path of the file,mode, permission parameter etc. to read the file into stream and hence it is used to read the text from file into stream. If we need to convert string to stream first we need to convert string to bytes array as stream is a sequence of bytes. Below is the code.
//Stream is a base class it holds the reference of MemoryStream
Stream stream = new MemoryStream();
String strText = "This is a String that needs to beconvert in stream";
byte[] byteArray = Encoding.UTF8.GetBytes(strText);
stream.Write(byteArray, 0, byteArray.Length);
//set the position at the beginning.
stream.Position = 0;
using (StreamReader sr = new StreamReader(stream))
{
string strData;
while ((strData= sr.ReadLine()) != null)
{
Console.WriteLine(strData);
}
}
I’ve been working on a function parsing 3rd party fms logs. The logs are in Gzip, so I use a decompressing function that works for any other Gzip files we use.
When decompressing these files I only get the first line of the compressed file, there’s no exception, it just doesn’t find the rest of the bytes as if there's an EOF at the first line.
I tried using Ionic.Zlib instead of System.IO.Compression but the result was the same. The files don’t seem to be corrupted in any way, decompressing them with Winrar works.
If anybody has any idea of how to solve this, I’ll appreciate your help.
Thanks
You can download a sample file here:
http://www.adjustyourset.tv/fms_6F9E_20120621_0001.log.gz
This is my decompression function:
public static bool DecompressGZip(String fileRoot, String destRoot)
{
try
{
using (FileStream fileStram = new FileStream(fileRoot, FileMode.Open, FileAccess.Read))
{
using (FileStream fOutStream = new FileStream(destRoot, FileMode.Create, FileAccess.Write))
{
using (GZipStream zipStream = new GZipStream(fileStram, CompressionMode.Decompress, true))
{
byte[] buffer = new byte[4096];
int numRead;
while ((numRead = zipStream.Read(buffer, 0, buffer.Length)) != 0)
{
fOutStream.Write(buffer, 0, numRead);
}
return true;
}
}
}
}
catch (Exception ex)
{
LogUtils.SaveToLog(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "Eror decompressing " + fileRoot + " : " + ex.Message, Constants.systemLog, 209715200, 6);
return false;
}
}
I've put the last 45 minutes wrapping my head around this problem but I just can't explain why it isn't working. Somehow the DeflateStream-class isn't decoding your data properly. I wrote up my own GZip-parser (I can share the code if anyone wants to check it) which reads all the headers and checks them for validity (to make sure that there are no funny stuff there) and then use DeflateStream to inflate the actual data but with your file it still just gets me the first line.
If I recompress using your logfile using GZipStream (after first decompressing it with winrar) then it is decompressed just fine again both my my own parser and your own sample.
There seems to be some critizism on the net about Microsofts implementation of Deflate (http://www.virtualdub.org/blog/pivot/entry.php?id=335) so it might be that you found one of it's quirks.
However, a simple solution to your problem is to switch to SharZipLib (http://www.icsharpcode.net/opensource/sharpziplib/), I tried it out and it can decompress your file just fine.
public static void DecompressGZip(String fileRoot, String destRoot)
{
using (FileStream fileStram = new FileStream(fileRoot, FileMode.Open, FileAccess.Read))
using (GZipInputStream zipStream = new GZipInputStream(fileStram))
using (StreamReader sr = new StreamReader(zipStream))
{
string data = sr.ReadToEnd();
File.WriteAllText(destRoot, data);
}
}