//© 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