//© 2007 Black Knight Technology Inc. As per clause 252.227-7014 under the contract N00178-04-D-3005 the Government has unlimited rights to this software.
namespace Universal.Converter
{
using System;
using System.IO;
using System.ComponentModel;
using BKTech.Chameleon.Plugins;
///
/// This plug-in splits its input files into smaller files.
///
/// This is useful for dealing with size limits of other programs
public class FileSplitter : IChameleonPlugin
{
#region "Private Members"
private int myMaxLines = 50000; //the maximum number of lines to write in each of the split files
private string[] myDataFiles; //the array of input files from the client
private FeedBack.sendFeedBack myReporter; //a delegate that allows this plug-in to send progress updates to the client
#endregion
#region "Public Properties"
[Browsable(false)]
public string Category
{
get { return "Converter"; }
}
[Browsable(false)]
public string Description
{
get
{
return "Takes each input file and splits it into smaller files, so that none have more lines than is specified in the custom properties section.";
}
}
[Browsable(false)]
public string ExpectedInput
{
get { return "Any text file"; }
}
[Browsable(false)]
public string Output
{
get { return "One or more files, each containing your specified maximum number of lines (or less)"; }
}
[Browsable(false)]
public string Author
{
get { return "Vincent Piattelli"; }
}
[Browsable(true), Description("The maximum number of lines you wish to have in each split file.")]
public int MaxLines
{
get { return this.myMaxLines; }
set { this.myMaxLines = value; }
}
#endregion
#region "Public Methods"
///
/// Initializes this plug-in
///
/// The array of input files from the client
/// A delegate for reporting status updates to the client
/// True if we are clear to begin execution, false if we have invalid input and need to abort
public bool Initialize(string[] dataFiles, FeedBack.sendFeedBack reporter)
{
myDataFiles = dataFiles;
myReporter = reporter;
if (myMaxLines < 1)
{
reporter("MaxLines must be 1 or greater!", FeedBack.ReturnCode.Failure);
return false;
}
return true;
}
///
/// The core logic of this plug-in
///
/// True if executed successfully, false otherwise
public bool Execute()
{
foreach (string dataFile in myDataFiles)
{
StreamReader reader = new StreamReader(dataFile);
StreamWriter writer = null;
int totalFiles = 0; //the number of files we have broken the input into thus far
try
{
string curLine = reader.ReadLine();
while (curLine != null)
{
//begin writing a new file
int numLinesWritten = 0; //how many lines we are into the current file
totalFiles++;
string outputname = GenerateFileName(dataFile); //generate a valid filename for the output
writer = new StreamWriter(outputname);
while (curLine != null && numLinesWritten < myMaxLines)
{
writer.WriteLine(curLine);
curLine = reader.ReadLine();
if (++numLinesWritten % 1000 == 0) myReporter(numLinesWritten.ToString() + " lines processed in file " + totalFiles.ToString(), FeedBack.ReturnCode.QuickUpdate);
}
myReporter("Wrote " + Path.GetFileName(outputname) + " with " + numLinesWritten.ToString() + " line(s)", FeedBack.ReturnCode.Success);
writer.Close();
}
myReporter(Path.GetFileName(dataFile) + " successfully broken into " + totalFiles.ToString() + " files of " + myMaxLines.ToString() + " lines or less.", FeedBack.ReturnCode.Success);
reader.Close();
}
catch (Exception e)
{
this.myReporter("Error reading or writing data", FeedBack.ReturnCode.Warning);
this.myReporter(e.Message, FeedBack.ReturnCode.Debug);
this.myReporter(e.StackTrace, FeedBack.ReturnCode.Debug);
return false; //something went wrong, so I'm going to bail out of this execution run.
}
finally
{
if (!Object.ReferenceEquals(writer, null))
{
writer.Close();
writer = null;
}
if (!Object.ReferenceEquals(reader, null))
{
reader.Close();
reader = null;
}
}
}
myReporter("FileSplitter has completed execution.", FeedBack.ReturnCode.Success);
return true;
}
///
/// Loads saved custom properties
///
/// The value saved by the client in the .cham file for this plug-in
/// True if loaded successfully, false if there was a problem
public bool Load(string loadValue)
{
if (loadValue.Length < 1) return true;
try
{
myMaxLines = Convert.ToInt32(loadValue);
return true;
}
catch
{
return false;
}
}
///
/// Saves this plug-in's data
///
/// A string equivalent of myMaxLines
public string Save()
{
return myMaxLines.ToString();
}
///
/// Cleans up this plug-in
///
/// Always true
/// No further processing is required because we
/// didn't allocate to any fancy data structures
public bool Clean()
{
return true;
}
#endregion
///
/// Ensures the generation of a unique file name
///
/// The file we want to derive a unique path from.
/// A complete, unique path .
private string GenerateFileName(string file)
{
int i = 1;
string path = Path.GetDirectoryName(file);
string baseFileName = Path.GetFileNameWithoutExtension(file);
string extension = Path.GetExtension(file);
string rootFileName = Path.Combine(path, baseFileName + "_split" + extension); //need to combine here for Exists check
string fileName = rootFileName;
while (File.Exists(fileName))
{
fileName = Path.Combine(path, Path.GetFileNameWithoutExtension(rootFileName) + "(" + i.ToString() + ")" + extension);
i++;
}
return fileName;
}
} //end class
} //end namespace