This splitter has been built because I didn't find a decent one in 5 minutes search. The reason behind a splitter is simple: Send files as an attachment (in my case using the gmail & gspace).
As for the code, I'm posting the full program here, and some highlights afterwards.
using System;
using System.Collections.Generic;
using System.Text;
namespace FileSplitter
{
class Program
{
const int DefalutBlockSize = 1000000;
private static byte[] STAMP = { 1, 2, 3 };
private static byte[] GetMD5(byte[] buf)
{
System.Security.Cryptography.MD5CryptoServiceProvider md = new System.Security.Cryptography.MD5CryptoServiceProvider();
md.Initialize();
return md.ComputeHash(buf);
}
private static void Split(string Filename, int BlockSize)
{
try
{
Console.WriteLine("Splitting " + Filename + " to " + BlockSize.ToString() + " bytes parts");
int part = 0;
byte[] buf;
System.IO.StreamReader in_fl = new System.IO.StreamReader(Filename);
System.IO.BinaryReader in_b = new System.IO.BinaryReader(in_fl.BaseStream);
while (true)
{
Console.WriteLine("Reading part " + part.ToString());
buf = in_b.ReadBytes(BlockSize);
if (buf.Length == 0)
{
in_b.Close();
Console.WriteLine("No more parts");
return;
}
Console.WriteLine("Writing part " + part.ToString());
System.IO.StreamWriter out_fl = new System.IO.StreamWriter(Filename + "." + part.ToString());
System.IO.BinaryWriter out_b = new System.IO.BinaryWriter(out_fl.BaseStream);
out_b.Write(STAMP);
byte[] MD = GetMD5(buf);
byte len = System.Convert.ToByte(MD.Length);
out_b.Write(len);
out_b.Write(MD);
out_b.Write(buf);
out_b.Flush();
out_b.Close();
part++;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private static void Merge(string Filename)
{
try
{
Console.WriteLine("Merging " + Filename);
int part = 0;
byte[] buf;
System.IO.StreamWriter out_fl = new System.IO.StreamWriter(Filename);
System.IO.BinaryWriter out_b = new System.IO.BinaryWriter(out_fl.BaseStream);
while (System.IO.File.Exists(Filename + "." + part.ToString()))
{
Console.WriteLine("Reading part " + part.ToString());
System.IO.StreamReader in_fl = new System.IO.StreamReader(Filename + "." + part.ToString());
System.IO.BinaryReader in_b = new System.IO.BinaryReader(in_fl.BaseStream);
buf = in_b.ReadBytes(STAMP.Length);
for (int i = 0; i < STAMP.Length; i++)
{
if (buf[i] != STAMP[i])
{
Console.WriteLine("Incorrect STAMP!");
Environment.Exit(2);
}
}
byte len = in_b.ReadByte();
byte[] file_MD = in_b.ReadBytes(System.Convert.ToInt32(System.Convert.ToInt32(len)));
buf = in_b.ReadBytes(System.Convert.ToInt32(in_b.BaseStream.Length));
byte[] calc_MD = GetMD5(buf);
for (int i = 0; i < calc_MD.Length; i++)
{
if (file_MD[i] != calc_MD[i])
{
Console.WriteLine("Incorrect HASH!");
Environment.Exit(3);
}
}
out_b.Write(buf);
out_b.Flush();
Console.WriteLine("Wrote part " + part.ToString());
part++;
}
out_b.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private static void ShowUsage()
{
Console.WriteLine("Usage: FileSplitter.exe -Filename <filename> [-blocksize <size>] [-stamp <file stamp>] {-split | -merge}");
Console.WriteLine("filename - the original filename");
Console.WriteLine("size - the size of the splitted parts");
Console.WriteLine("stamp - the header of the splitted parts");
Console.WriteLine("Parameters can be used more than once in the string, each split/merge is ran with the \"current\" values");
}
static void Main(string[] args)
{
Console.WriteLine("File splitting / merging utility by Liron");
Console.WriteLine("This utility is available as is.\r\n");
string Filename = "";
int BlockSize = DefalutBlockSize;
for (int i = 0; i < args.Length; i++)
{
switch (args[i].ToLower())
{
case "-stamp":
i++;
STAMP = new byte[args[i].Length];
for (int j = 0; j < args[i].Length; j++)
{
STAMP[j] = System.Convert.ToByte(args[i][j]);
}
break;
case "-filename":
i++;
Filename = args[i];
break;
case "-blocksize":
i++;
BlockSize = System.Convert.ToInt32(args[i]);
break;
case "-split":
Split(Filename, BlockSize);
break;
case "-merge":
Merge(Filename);
break;
case "-h":
ShowUsage();
Environment.Exit(0);
break;
default:
ShowUsage();
Environment.Exit(255);
break;
}
}
}
}
}
Some highlights
Note the way the HASH is added. The resulting file is in the following structure:
[STAMP][HASH length][HASH][Original part]
This structure allows an easy reconnection of the parts, plus a check for errors.
Another thing related to the structure is the fact that the resulting size would be BLOCKSIZE + HEADERSIZE which is slightly beigger than the intended size. It can be fixed quite easily by reading BLOCKSIZE - HEADERSIZE bytes instead of BLOCKSIZE bytes. I didn't need it so I left it out.
The most important note: This code has the minimal checks, if you want to use it, you'll need to add some checks (users can do many strange things if there's no check)
Wednesday, February 13, 2008
Wednesday, February 6, 2008
C# vs VBScript
After writing another VBScript script for our System I began wondering what's the difference in performance between a script and a compiled program.
So I began by writing a nice VBScript that does heavy calculation (I used the calculation of n! for n=1 to 100) Using a normal computer it takes almost no time, well, repeat it for 10000 times... The script I wrote is:
Option Explicit
Call Main()
Sub Main()
Dim StartingTime
Dim EndingTime
StartingTime = Now()
Call DoHardWork(100)
EndingTime = Now()
WScript.Echo "Started at: " & StartingTime
WScript.Echo "Finished at: " & EndingTime
WScript.Echo "Total time: " & DateDiff("s",StartingTime,EndingTime) & " sec"
End Sub
Sub DoHardWork(MaxI)
Dim i
Dim j
For j = 1 To 10000
For i = 1 To MaxI
Call RecursiveCalc(i)
Next
Next
End Sub
Function RecursiveCalc(CurNum)
If curnum = 1 Then
RecursiveCalc = 1
Else
RecursiveCalc = CurNum * RecursiveCalc (CurNum - 1)
End If
End Function
Dumb, does the job using no cache and other enhancements. The script took 107s on my computer. I felt this is a good benchmark, I'll write a simple C# program and run it. How fast can it be? The C# program I wrote is almost an exact copy of the VBS:
using System;
using System.Collections.Generic;
using System.Text;
namespace TimeCheck
{
class Program
{
static void Main(string[] args)
{
DateTime StartingTime = DateTime.Now;
DoHardWork(100);
DateTime EndingTime = DateTime.Now;
Console.WriteLine("Started at: " + StartingTime.ToString());
Console.WriteLine("Finished at: " + EndingTime.ToString());
Console.WriteLine("Total time: " + EndingTime.Subtract(StartingTime).ToString());
}
static void DoHardWork(int MaxI)
{
for (int j = 1; j < 10000; j++)
{
for (int i = 1; i < MaxI; i++)
{
RecursiveCalc(i);
}
}
}
static long RecursiveCalc(int CurNum)
{
if (CurNum == 1)
{
return 1;
}
else
{
return CurNum * RecursiveCalc(CurNum - 1);
}
}
}
}
The results are: 1.57464s for the "Debug" compilation.
The "Release" took 1.023516s. If anyone needs a reminding of the difference between programs and scripts.
P.S. if anyone wants to do the same test in another language, please send me the results, I'd like to add more to the results chart in the future.
So I began by writing a nice VBScript that does heavy calculation (I used the calculation of n! for n=1 to 100) Using a normal computer it takes almost no time, well, repeat it for 10000 times... The script I wrote is:
Option Explicit
Call Main()
Sub Main()
Dim StartingTime
Dim EndingTime
StartingTime = Now()
Call DoHardWork(100)
EndingTime = Now()
WScript.Echo "Started at: " & StartingTime
WScript.Echo "Finished at: " & EndingTime
WScript.Echo "Total time: " & DateDiff("s",StartingTime,EndingTime) & " sec"
End Sub
Sub DoHardWork(MaxI)
Dim i
Dim j
For j = 1 To 10000
For i = 1 To MaxI
Call RecursiveCalc(i)
Next
Next
End Sub
Function RecursiveCalc(CurNum)
If curnum = 1 Then
RecursiveCalc = 1
Else
RecursiveCalc = CurNum * RecursiveCalc (CurNum - 1)
End If
End Function
Dumb, does the job using no cache and other enhancements. The script took 107s on my computer. I felt this is a good benchmark, I'll write a simple C# program and run it. How fast can it be? The C# program I wrote is almost an exact copy of the VBS:
using System;
using System.Collections.Generic;
using System.Text;
namespace TimeCheck
{
class Program
{
static void Main(string[] args)
{
DateTime StartingTime = DateTime.Now;
DoHardWork(100);
DateTime EndingTime = DateTime.Now;
Console.WriteLine("Started at: " + StartingTime.ToString());
Console.WriteLine("Finished at: " + EndingTime.ToString());
Console.WriteLine("Total time: " + EndingTime.Subtract(StartingTime).ToString());
}
static void DoHardWork(int MaxI)
{
for (int j = 1; j < 10000; j++)
{
for (int i = 1; i < MaxI; i++)
{
RecursiveCalc(i);
}
}
}
static long RecursiveCalc(int CurNum)
{
if (CurNum == 1)
{
return 1;
}
else
{
return CurNum * RecursiveCalc(CurNum - 1);
}
}
}
}
The results are: 1.57464s for the "Debug" compilation.
The "Release" took 1.023516s. If anyone needs a reminding of the difference between programs and scripts.
P.S. if anyone wants to do the same test in another language, please send me the results, I'd like to add more to the results chart in the future.
Subscribe to:
Posts (Atom)