Can't Use Stream.Write method while playing same file in MediaElement - c#

So lets say I have a file which has around 2MB already downloaded and written which is being played using a MediaElement. So while the media is being played, I want to download and write the rest of the file.
If I use this method, I get an IOExecption error indicating the file is already in use.
using (Stream WriteStream = new FileStream(filename, FileMode.OpenOrCreate))
{
WriteStream.Seek(seekpos, SeekOrigin.Begin);
WriteStream.Write(buffer, 0, buffer.Length);
WriteStream.Close();
}
But if I use this method, it works fine.
FileStream1 = new System.IO.FileStream(filename, System.IO.FileMode.Append, System.IO.FileAccess.Write, System.IO.FileShare.ReadWrite);
FileStream1.Write(buffer, 0, buffer.Length);
So I could use the second method, but I want to be able to seek and write at certain positions which I can't do using the second method. So is there anyway in which I can use the first method. Does it have something to do with the FILEMODE or FILEACCESS?
Thanks :)

The closest you might get might be displayed here with what's known as a synchronized stream. Essentially, it's multiple threads acting on the same stream. You'd have to get the locking issue resolved, especially since you may have no way of making the MediaElement open the file with a shared lock.
Another approach might be to write to one file while the MediaElement plays from another. When the MediaElement's done with file A, play B and stream downloads to new file C. Repeat. Then, at the end, merge them together.

Never-mind I figured it out. I can use this to seek and write at any position. Stupid of me to not realise this.
FileStream1 = new System.IO.FileStream(filename, System.IO.FileMode.Append, System.IO.FileAccess.Write, System.IO.FileShare.ReadWrite);
FileStream1.Seek(seekpos,SeekOrigin.Begin);
FileStream1.Write(buffer, 0, buffer.Length);

Related

c# FileStream (FileAccess.Read) block other programs acess on .Close()

I have a program that copies video files, while they are being played.
More often than not, the video player (3rd party) is unable to access the file for around half a second (playback freezes) whenever I Close() the FileStream in my program.
From what I can tell, it won't matter if I use Dispose() instead of Close().
The file is copied to the new location as expected, so the playback freeze is the issue I need to solve, but frankly I do not know the specifics on how the 3rd party software reads the file.
I just can't wrap my head around why the problem appears exactly when I close the reading stream.
I would like to avoid having to postpone the copy process until the video player is done playing.
Any suggestions will be appreciated.
FileStream SourceFile = new FileStream(sourcePath, FileMode.Open, FileAccess.Read);
while(bytesLeftToCopy > 0)
{
int _BlockSize = 1024 * 1024;
byte[] _BlockBuffer = new byte[_BlockSize];
SourceFileBytes = SourceFile.Read(_BlockBuffer, 0, _BlockSize);
//you get the idea
}
SourceFile.Close();
Have you tried wrap your filestream into using construction? It automatically disposes the object after execution.
using (FileStream SourceFile = new FileStream(sourcePath, FileMode.Open, FileAccess.Read))
{
//read
}
Sorry to have bothered you guys, but it turns out that the problem was in the writing part of the program.
The guy who wrote this didn't flush the writing stream, which meant alot of data was cached when the read loop came to an end. Which in turn meant alot of system resources were used at Close() time.
I switched to the constructor (for the write stream) that accepts the FileOptions.WriteThough argument. This seems to have solved the problem.
Thanks for the suggestions you provided... I'll try to be more thorough when I create my next questions.

Read audio file to stream with MediaPlayer (WPF)

I use MediaPlayer to play audio files
var mediaPlayer = new MediaPlayer();
mediaPlayer.Open(new Uri(s));
mediaPlayer.Play();
Sometimes I need to delete files that MediaPlayer is still playing.
I guess I have somehow read file to stream to be get free access to it in order to delete it. I mean i sthere way to read file to stream or I have to create some temp. file to play and in this case I can delete the original one or there are other options?
How to implement it?
Thank you!
Actually, when you call MediaPlayer.Open it reads in the file via a stream automatically. The problem is that the stream is still open when you try to delete the file.
MediaPlayer has a .Close method on it. Calling this will close the stream that's reading in the file.
here's the documentation on the MediaPlayer class so you can see what other methods are available to use: http://msdn.microsoft.com/en-us/library/system.windows.media.mediaplayer.aspx
EDIT: If you don't mind that the player stops playback when you call Close then you can just Close & then delete your file. If you do need playback to continue then you'll need a different approach.
If you're using Silverlight then you can just load the stream directly into a MediaElement:
var bytes = File.ReadAllBytes(#"c:\yourfile.ext");
var mStream = new MemoryStream(bytes);
mediaElement1.SetSource(mStream);
Sadly, WPF does not have the same stream support. I attempted to get a Uri for the MemoryStream by writing the stream into the resource pack. Though, i couldn't get it to playback correctly in my testing. I'll include my source that i had just in case you want to fiddle with it and maybe get it to work:
var bytes = File.ReadAllBytes(#"C:\Bill\TestWaveFiles\14043.wav");
MemoryStream packStream = new MemoryStream()
Package pack = Package.Open(packStream, FileMode.Create, FileAccess.ReadWrite);
Uri packUri = new Uri("bla:");
PackageStore.AddPackage(packUri, pack);
Uri packPartUri = new Uri("/MemoryResource", UriKind.Relative);
PackagePart packPart = pack.CreatePart(packPartUri, "Media/MemoryResource");
packPart.GetStream().Write(bytes, 0, bytes.Length);
var inMemoryUri = PackUriHelper.Create(packUri, packPart.Uri);
mediaElement1.LoadedBehavior = MediaState.Manual;
mediaElement1.Source = inMemoryUri;
mediaElement1.Play();
Another option is to simply make a copy of the file before you open it. that way you can always delete the original. Though, you could also just "mark" the file to be deleted. When the user is done playing the the file then you could close & delete it.
One additional option is to use a 3rd party library called BoxedApp. It seemingly will allow you to have a "Virtual File" that contains a memory stream. You could then get a Uri that points to this virtual file and load it into the media player. Look at this answer by
user1108125 to see how to use this BoxedApp library (which i've never used). https://stackoverflow.com/a/8587166/1721136

How to put three files into one in c#?

I'm trying to make a map for a game that I'm planning to create. The map should have two data files, and a picture file.
I want to put them together, to form a single file, and I only want to use the default libraries.
How can I do this, and still be able to separate them later?
A solution would be compression, but I couldn't find a way to compress multiple files using the gzipstreamer class.
You could use SharpZipLib to create a ZIP file.
Did you consider embedding the files as resources in the assembly (or in a separate assembly?)
A lot depends on the reasons why you want to group them.
Compression will cost time and CPU power.
I think you should consider embedding the resources in the assembly as Erno suggests.
But if you really want to pack them into a single file, you could do so by simply writing the length of each stream before the stream itself. You could then read the length byte and afterwards return the next length bytes as a Stream. Reading/writing with ugly methods below. The target stream could eventually be gzipped. Note that the naive methods below reads and writes the entire string to a single buffer and assumes that no file is larger than int.MaxValue.
But I would not recommend using just the standard libraries.
static void Append(Stream source, Stream target)
{
BinaryWriter writer = new BinaryWriter(target);
BinaryReader reader = new BinaryReader(source);
writer.Write((long)source.Length);
byte[] buffer = new byte[1024];
int read;
do
{
read = reader.Read(buffer, 0, buffer.Length);
writer.Write(buffer, 0, read);
}
while (read > 0);
writer.Flush();
}
static Stream ReadNextStream(Stream packed)
{
BinaryReader reader = new BinaryReader(packed);
int streamLength = (int)reader.ReadInt64();
MemoryStream result = new MemoryStream();
byte[] buffer = new byte[streamLength];
reader.Read(buffer, 0, buffer.Length);
BinaryWriter writer = new BinaryWriter(result);
writer.Write(buffer, 0, buffer.Length);
writer.Flush();
result.Seek(0, SeekOrigin.Begin);
return result;
}
Gzip compression only works on one file (it only ever has). You could try ZIP, 7-ZIP or some other archive format that allows multiple files. Alternately you can TAR the files together first, which was common practice for the compression scheme Gzip was invented to replace.
I had a simiar question a while ago here about saving 2 XML files in one file.
See my answer with code.
"I ended up writing my own Stream, which can be thought of as a multistream. It allows you to treat one stream as multiple streams in succession. i.e. pass a multistream to an xml parser (or anything else) and it'll read up to a marker, which says 'this is the end of the stream'. If you then pass that same stream to another xml parser, it'll read from that marker, to the next one or EOF"
Your basic usage would be:
Writing:
Open File Stream
Create MultiStream passing in File Stream in constructor
Write data file to multistream
Call write end of stream marker on multistream
Write 2nd data file to multistream
Call write end of stream marker on multistream
Save picture to multistream
Close multistream
Close file stream
Reading:
Open File Stream
Create MultiStream passing in File Stream in constructor
Read data file
Call advance to next stream on multistream
Read 2nd data file
Call advance to next stream on multistream
Read image (Image.FromStream() etc.)
Close multistream
Close file stream

.Net MemoryStream close issue

For a .Net MemoryStream object instance, do I need to close it explicitly after using it? Or no need to close it? Which is the best practices?
I am using VSTS2008 + .Net 3.5 + C#.
Better yet would be to use Using
using (MemoryStream ms = /*get it using your favorite ctor*/)
{
// use it here
// and now flush and copy to a file stream (for example)
ws.Flush();
byte[] buffer = ws.ToArray();
using (Stream stream = new FileStream("fileName", FileMode.Create))
stream.Write(buffer, 0, buffer.Length);
}
A little reminder - if you plan to write it all into another stream at the end, don't forget to Flush() (And don't leave the toilet seat up).
I use a StreamWriter around the ms, to write text data into the memory, and at the end put it all on disc in one go. (I can also change the example here to this case, if you'd like)
you should close it when you are done with it. The best practice is to close the stream in the finally section of a try-catch-finally block. you can get more information here:
http://msdn.microsoft.com/en-us/library/system.io.memorystream.aspx

Joining Binary files that have been split via download

I am trying to join a number of binary files that were split during download. The requirement stemmed from the project http://asproxy.sourceforge.net/. In this project author allows you to download files by providing a url.
The problem comes through where my server does not have enough memory to keep a file that is larger than 20 meg in memory.So to solve this problem i modified the code to not download files larger than 10 meg's , if the file is larger it would then allow the user to download the first 10 megs. The user must then continue the download and hopefully get the second 10 megs. Now i have got all this working , except when the user needs to join the files they downloaded i end up with corrupt files , as far as i can tell something is either being added or removed via the download.
I am currently join the files together by reading all the files then writing them to one file.This should work since i am reading and writing in bytes. The code i used to join the files is listed here http://www.geekpedia.com/tutorial201_Splitting-and-joining-files-using-C.html
I do not have the exact code with me atm , as soon as i am home i will post the exact code if anyone is willing to help out.
Please let me know if i am missing out anything or if there is a better way to do this , i.e what could i use as an alternative to a memory stream. The source code for the original project which i made changes to can be found here http://asproxy.sourceforge.net/download.html , it should be noted i am using version 5.0. The file i modified is called WebDataCore.cs and i modified line 606 to only too till 10 megs of data had been loaded the continue execution.
Let me know if there is anything i missed.
Thanks
You shouldn't split for memory reasons... the reason to split is usually to avoid having to re-download everything in case of failure. If memory is an issue, you are doing it wrong... you shouldn't be buffering in memory, for example.
The easiest way to download a file is simply:
using(WebClient client = new WebClient()) {
client.DownloadFile(remoteUrl, localPath);
}
Re your split/join code - again, the problem is that you are buffering everything in memory; File.ReadAllBytes is a bad thing unless you know you have small files. What you should have is something like:
byte[] buffer = new byte[8192]; // why not...
int read;
while((read = inStream.Read(buffer, 0, buffer.Length)) > 0)
{
outStream.Write(buffer, 0, read);
}
This uses a moderate buffer to pump data between the two as a stream. A lot more efficient. The loop says:
try to read some data (at most, the buffer-size)
(this will read at least 1 byte, or we have reached the end of the stream)
if we read something, write this many bytes from the buffer to the output
In the end i have found that by using a FTP request i was able to get arround the memory issue and the file is saved correctly.
Thanks for all the help
That example is loading each entire chunk into memory, instead you could do something like this:
int bufSize = 1024 * 32;
byte[] buffer = new byte[bufSize];
using (FileStream outputFile = new FileStream(OutputFileName, FileMode.OpenOrCreate,
FileAccess.Write, FileShare.None, bufSize))
{
foreach (string inputFileName in inputFiles)
{
using (FileStream inputFile = new FileStream(inputFileName, FileMode.Append,
FileAccess.Write, FileShare.None, buffer.Length))
{
int bytesRead = 0;
while ((bytesRead = inputFile.Read(buffer, 0, buffer.Length)) != 0)
{
outputFile.Write(buffer, 0, bytesRead);
}
}

Categories