This question already has an answer here:
In your code, when you open the FileMp3Reader
, uses the word Action
and then placed inside by using a Lambda expression, a method.
What does the keyword Action
?
Inside the file.Create
method what is being done?
var mp3Path = @"C:\Users\ronnie\Desktop\mp3\dotnetrocks_0717_alan_dahl_imagethink.mp3";
int splitLength = 120;
var mp3Dir = Path.GetDirectoryName(mp3Path);
var mp3File = Path.GetFileName(mp3Path);
var splitDir = Path.Combine(mp3Dir,Path.GetFileNameWithoutExtension(mp3Path));
Directory.CreateDirectory(splitDir);
int splitI = 0;
int secsOffset = 0;
using (var reader = new Mp3FileReader(mp3Path))
{
FileStream writer = null;
Action createWriter = new Action(() => {
writer = File.Create(Path.Combine(splitDir,Path.ChangeExtension(mp3File,(++splitI).ToString("D4") + ".mp3")));
});
Mp3Frame frame;
while ((frame = reader.ReadNextFrame()) != null)
{
if (writer == null) createWriter();
if ((int)reader.CurrentTime.TotalSeconds - secsOffset >= splitLength)
{
writer.Dispose();
createWriter();
secsOffset = (int)reader.CurrentTime.TotalSeconds;
}
writer.Write(frame.RawData, 0, frame.RawData.Length);
}
if(writer != null) writer.Dispose();
}
As noted in the comments, Action
here is a delegate type. Which, given it's placement in the variable declaration, probably could have been inferred by many readers from the context. :)
The code in the File.Create()
method simply generates a new file name based on the splitI
index.
Ironically, in this particular case, the use of Action
is superfluous. The code really should not have been written this way, as the delegate just makes it harder to read. A better version looks like this:
using (var reader = new Mp3FileReader(mp3Path))
{
FileStream writer = null;
try
{
Mp3Frame frame;
while ((frame = reader.ReadNextFrame()) != null)
{
if (writer != null &&
(int)reader.CurrentTime.TotalSeconds - secsOffset >= splitLength)
{
writer.Dispose();
writer = null;
secsOffset = (int)reader.CurrentTime.TotalSeconds;
}
if (writer == null)
writer = File.Create(Path.Combine(splitDir,
Path.ChangeExtension(mp3File,(++splitI).ToString("D4") + ".mp3")));
writer.Write(frame.RawData, 0, frame.RawData.Length);
}
}
finally
{
if(writer != null) writer.Dispose();
}
}
That way, the work to create a new FileStream
instance is only ever needed in one place.
Even if it were really required to call it from two different places, IMHO this particular scenario would call for named method instead. The code would have been more readable that way, than using the delegate instance.
Path.ChangeExtension(mp3File,(++splitI).ToString("D4") + ".mp3")));
- missennasplitI
), which is used to create file names of the form <original name>XXXX.mp3
where <original name>
is of course the name of the original file, XXXX
is the four-digit, zero-padding index of the segment being written, and of course .mp3
is the extension. This allows the loop to write out the original single file, as partial segments, each an MP3 clip no longer than splitLength
in seconds. If you need more than that, you should post another question asking for specifics - Peter Duniho