Something like System.Diagnostics.Process.Start to run a stream - c#

I get from server images and videos by stream.
Now I'm saving it:
Stream str = client.GetFile(path);
using (var outStream = new FileStream(#"c:\myFile.jpg", FileMode.Create))
{
var buffer = new byte[4096];
int count;
while ((count = str.Read(buffer, 0, buffer.Length)) > 0)
{
outStream.Write(buffer, 0, count);
}
}
I can be jpg, mpg, flv and a lot of other multimedia types (Before I get stream I know what is a extension of this file).
Now I want to not save it , but run direct from stream.
Examples:
I get stream which is mybirthay.avi and I call my method RunFile(stream) and I think this method should works like System.Diagnostics.Process.Start(path), so my stream should be opened by default program in my SO for example allplayer.
I get stream from myfile.jpg and it is opening by irfanview,
etc...
Is it possible ??

If you are set on not saving the stream to the disk, you could use something like Eldos' Callback File System: http://www.eldos.com/cbfs/
Or, use a ramdisk, save your stream there, and shell to that file location.

Windows puts up a wall between processes so they cannot directly access each other's memory without going through privileged debug-like API functions like ReadProcessMemory. This is what keeps the operating system stable and secure. But spells doom for what you are trying to accomplish.
You'll need to use a file. It won't be much slower than direct memory access, the file system cache takes care of that.

Related

Streaming a large file into a database BLOB field

I have a large file on disk whose contents I need to store in a SqlServer database as a VARBINARY(MAX) field. By "contents", I mean using something like File.ReadAllBytes(). (I understand the pitfalls of this, but it's the current mode of operations, so I have to deal with it for now.)
I found this answer, which provides a way to stream a large Byte[] by using UPDATE.WRITE:
How to I serialize a large graph of .NET object into a SQL Server BLOB without creating a large buffer?
However, simply reading the contents of a large file into a Byte[] in memory leads to this problem:
OutOfMemoryException when I read 500MB FileStream
I might be overlooking something obvious, but I just can't work out how should I go about getting from a large file on disk, to the resulting storage into the database.
Using some hints I got from these two pages, I have an answer that works:
http://www.syntaxwarriors.com/2013/stream-varbinary-data-to-and-from-mssql-using-csharp/ (this looks a lot like the serialize SO answer, but there's more here...not sure who copied who!).
How do I copy the contents of one stream to another?
Basically, it uses the same methodology as the answer about serializing Blobs, but instead of using BinaryFormatter (a class I'm not fond of anyhow), it creates a FileStream that takes the path to the file, and an extension method to copy that stream into the target stream, or BlobStream, as the example named it.
Here's the extension:
public static class StreamEx
{
public static void CopyTo(this Stream Input, Stream Output)
{
var buffer = new Byte[32768];
Int32 bytesRead;
while ((bytesRead = Input.Read(buffer, 0, buffer.Length)) > 0)
Output.Write(buffer, 0, bytesRead);
}
}
So the trick was to link two streams, copying the data from one to another in chunked fashion, as noted in the comments.

Principles behind FileStreaming

I've been working on a project recently that involves a lot of FileStreaming, something which I've not really touched on before.
To try and better acquaint myself with the principles of such methods, I've written some code that (theoretically) downloads a file from one dir to another, and gone through it step by step, commenting in my understanding of what each step achieves, like so...
Get fileinfo object from DownloadRequest Object
RemoteFileInfo fileInfo = svr.DownloadFile(request);
DownloadFile method in WCF Service
public RemoteFileInfo DownloadFile(DownloadRequest request)
{
RemoteFileInfo result = new RemoteFileInfo(); // create empty fileinfo object
try
{
// set filepath
string filePath = System.IO.Path.Combine(request.FilePath , #"\" , request.FileName);
System.IO.FileInfo fileInfo = new System.IO.FileInfo(filePath); // get fileinfo from path
// check if exists
if (!fileInfo.Exists)
throw new System.IO.FileNotFoundException("File not found",
request.FileName);
// open stream
System.IO.FileStream stream = new System.IO.FileStream(filePath,
System.IO.FileMode.Open, System.IO.FileAccess.Read);
// return result
result.FileName = request.FileName;
result.Length = fileInfo.Length;
result.FileByteStream = stream;
}
catch (Exception ex)
{
// do something
}
return result;
}
Use returned FileStream from fileinfo to read into a new write stream
// set new location for downloaded file
string basePath = System.IO.Path.Combine(#"C:\SST Software\DSC\Compilations\" , compName, #"\");
string serverFileName = System.IO.Path.Combine(basePath, file);
double totalBytesRead = 0.0;
if (!Directory.Exists(basePath))
Directory.CreateDirectory(basePath);
int chunkSize = 2048;
byte[] buffer = new byte[chunkSize];
// create new write file stream
using (System.IO.FileStream writeStream = new System.IO.FileStream(serverFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
do
{
// read bytes from fileinfo stream
int bytesRead = fileInfo.FileByteStream.Read(buffer, 0, chunkSize);
totalBytesRead += (double)bytesRead;
if (bytesRead == 0) break;
// write bytes to output stream
writeStream.Write(buffer, 0, bytesRead);
} while (true);
// report end
Console.WriteLine(fileInfo.FileName + " has been written to " + basePath + " - Done!");
writeStream.Close();
}
What I was hoping for is any clarification or expansion on what exactly happens when using a FileStream.
I can achieve the download, and now I know what code I need to write in order to perform such a download, but I would like to know more about why it works. I can find no 'beginner-friendly' or step by step explanations on the web.
What is happening here behind the scenes?
A stream is just an abstraction, fundamentally it works like a pointer within a collection of data.
Take the example string of "Hello World!" for example, it is just a collection of characters, which are fundamentally just bytes.
As a stream, it could be represented to have:
A length of 12 (possibly more including termination characters etc)
A position in the stream.
You read a stream by moving the position around and requesting data.
So reading the text above could be (in pseudocode) seen to be like this:
do
get next byte
add gotten byte to collection
while not the end of the stream
the entire data is now in the collection
Streams are really useful when it comes to accessing data from sources such as the file system or remote machines.
Imagine a file that is several gigabytes in size, if the OS loaded all of that into memory any time a program wanted to read it (say a video player), there would be a lot of problems.
Instead, what happens is the program requests access to the file, and the OS returns a stream; the stream tells the program how much data there is, and allows it to access that data.
Depending on implementation, the OS may load a certain amount of data into memory ahead of the program accessing it, this is known as a buffer.
Fundamentally though, the program just requests the next bit of data, and the OS either gets it from the buffer, or from the source (e.g. the file on disk).
The same principle applies to streams between different computers, except requesting the next bit of data may very well involve a trip to the remote machine to request it.
The .NET FileStream class and the Stream base class, all just defer to the windows systems for working with streams in the end, there's nothing particularly special about them, it's just what you can do with the abstraction that makes them so powerful.
Writing to a stream is just the same, but it just puts data into the buffer, ready for the requester to access.
Infinite Data
As a user pointed out, streams can be used for data of indeterminate length.
All stream operations take time, so reading a stream is typically a blocking operation that will wait until data is available.
So you could loop forever while the stream is still open, and just wait for data to come in - an example of this in practice would be a live video broadcast.
I've since located a book - C# 5.0 All-In-One For Dummies - It explains everything about all Stream classes, how they work, which one is most appropriate and more.
Only been reading about 30 minutes, already have such a better understanding. Excellent guide!

C# The Process Cannot Access the File (2nd time only)

I am trying download an image from a website and put it in a picturebox.
// response contains HttpWebResponse of the page where the image is
using (Stream inputStream = response.GetResponseStream()) {
using (Stream outputStream = File.Open(fileName, FileMode.Create)) {
byte[] buffer = new byte[4096];
int bytesRead;
do {
bytesRead = inputStream.Read(buffer, 0, buffer.Length);
outputStream.Write(buffer, 0, bytesRead);
} while (bytesRead != 0);
}
}
response.Close();
After that, the downloaded image is assigned to a PictureBox like such:
if (imageDownloaded) {
pictureBox1.Image = Image.FromFile(filePath);
}
This all works like a charm first time, but the second time I run the code I get System.IO.IOException: "Additional information: The process cannot access the file ...(file path) ... because it is being used by another process.". I have no idea why...
I looked at 4 other threads such as this one, but they were basically stressing out the need to close streams, which I do, so none of them helped me.
Before you recommend to use pictureBox1.Load() I can't because I need the image downloaded for further development.
EDIT 1: I have actually tried to dispose the image by putting pictureBox1.Image = null before the code above is executed. It is still giving me an exception.
The Image.FromFile docs state:
The file remains locked until the Image is disposed.
So you need to dispose your Image too to be able to overwrite the file.
Try using the Clone method on your image and dispose the original Image.
The thing is related to the Image.FromFile. If we read a documentation, there is a note:
The file remains locked until the Image is disposed.
This pretty much explains the behavior you get.
To resolve this, you might need to create a copy of the image and assign it to a PictureBox .
From MSDN:
The file remains locked until the Image is disposed.
This means its the PictureBox that is holding the file open.
You have two options:
Dispose of the PictureBox image before writing the new file.
Download the file, make a copy of it and load the copy into the PictureBox - this allows you to write over the downloaded file freely.
I'll be the contrarian here. :)
While cloning/copying the image will resolve the exception, it raises a different question: why are you overwriting to the same file for a new image?
It seems to me that a better approach would be to download subsequent files to different file names (if they are really different files), or to simply reuse the file already downloaded instead of hitting the network again (if it's just a new request for the same file).
Even if you want to repeatedly download the same file (perhaps you expect the actual file contents to change), you can still download to a new name (e.g. append a number to the file name, use a GUID for the local file name, etc.)

How to open a file from Memory Stream

Is it possible to open a file directly from a MemoryStream opposed to writing to disk and doing Process.Start() ? Specifically a pdf file? If not, I guess I need to write the MemoryStream to disk (which is kind of annoying). Could someone then point me to a resource about how to write a MemoryStream to Disk?
It depends on the client :) if the client will accept input from stdin you could push the dta to the client. Another possibility might be to write a named-pipes server or a socket-server - not trivial, but it may work.
However, the simplest option is to just grab a temp file and write to that (and delete afterwards).
var file = Path.GetTempFileName();
using(var fileStream = File.OpenWrite(file))
{
var buffer = memStream.GetBuffer();
fileStream.Write(buffer, 0, (int)memStream.Length);
}
Remember to clean up the file when you are done.
Path.GetTempFileName() returns file name with '.tmp' extension, therefore you cant't use Process.Start() that needs windows file association via extension.
If by opening a file, you mean something like starting Adobe Reader for PDF files, then yes, you have to write it to a file. That is, unless the application provides you with some API do that.
One way to write a stream to file would be:
using (var memoryStream = /* create the memory stream */)
using (var fileStream = File.OpenWrite(fileName))
{
memoryStream.WriteTo(fileStream);
}

Record HTTP Audio stream to file

In C# I want to record an audio stream
I am doing something along the lines of:
HttpWebRequest req;
req = (HttpWebRequest)WebRequest.Create("http://url.com/stream");
Webresponse resp = req.GetResponse();
Stream s = resp.GetResponseStream();
fs = File.Exists(fileName)
? new FileStream(fileName, FileMode.Append)
: new FileStream(fileName, FileMode.Create);
byte[] buffer = new byte[4096];
while (s.CanRead)
{
Array.Clear(buffer, 0, buffer.Length);
total += s.Read(buffer, 0, buffer.Length);
fs.Write(buffer, 0, buffer.Length);
}
and the file size grows but can't be played back by VLC or any other program.
This is not my exact code I do a lot of error checking etc, but this gives the general idea.
Array.Clear(buffer, 0, buffer.Length);
total += s.Read(buffer, 0, buffer.Length);
fs.Write(buffer, 0, buffer.Length);
You do not have to clear the whole array before you read - there's no point in doing this. But you have to check how many bytes you actually read, there's no guarantee the whole array is filled every time (and it probably won't):
int bytesRead = s.Read(buffer, 0, buffer.Length);
fs.Write(buffer, 0, bytesRead);
total+=bytesRead;
Also whether the file plays (even when it is not corrupted anymore once you fix the file writing code) back depends on the format that you are downloading - what codec / file type is it?
THe problem is the streamed bits don't have context. When you stream to an application, there is a tacit agreement that you are dealing with file type X and the streaming program then tries to play the bits.
WHen you stream to a file, you have to add the context. One of the most important bits is the header identifying the type of file and other information.
If you can add the header, you can play the file from the file system. The header will not be part of the stream, as the server and client have agreed on what type fo file it it is already.
If you create a streaming player, you can possibly play back the bits you saved, as you negotiate the type. BUt to have it automagically work from file, you have to add the header.
Trying to save streamed MP3 audio to disk is essentially impossible without a detailed understanding of both the stream format and the file format for MP3. What you're getting from the stream is a series of "windowed" chunks of audio converted to frequency domain; the player receiving the stream converts the chunks back into time-domain audio on the fly and plays them one after the other.
To make an MP3 file, you would have to first write out a header containing the format information and then write each chunk of data. But most likely the format for storing these chunks in a file is different from the way in which they're compacted into a stream.
Sorry, but I would seriously advise you to give this up. One major reason that music services stream instead of offering file downloads is specifically because it's so difficult to save an MP3-type stream to disk (it would be a trivial matter to save an uncompressed audio stream to a WAV file).

Categories

Resources