/// <see cref="IIntegerFileInfoCollector.GetIntegerFileInfo(string, int)"/> public IntegerFileInfo GetIntegerFileInfo(string filePath, int chunkSize) { Debug.Assert(filePath != null); Debug.Assert(chunkSize > 0); IntegerFileInfo fileInfo = new IntegerFileInfo() { NumOfChunks = 0, NumOfIntegers = 0 }; //Open a text reader to the file using (StreamReader fileReader = fileIO.CreateFileStreamReader(filePath)) { while (!fileReader.EndOfStream) { //Read each line to count the number of lines in the file fileReader.ReadLine(); fileInfo.NumOfIntegers++; } } //Now that we have the number of integers, calculate the number of chunks fileInfo.NumOfChunks = (int)Math.Ceiling(Decimal.Divide(fileInfo.NumOfIntegers, chunkSize)); return(fileInfo); }
/// <summary> /// Sorts the integers found in an input file and writes the sorted integers to an output file /// </summary> /// <param name="options">The command line options</param> private static List <string> SortIntegers(CommandLineOptions options) { IFileIO fileIO = serviceProvider.GetService <IFileIO>(); IIntegerFileInfoCollector integerFileInfoCollector = serviceProvider.GetService <IIntegerFileInfoCollector>(); //Find the output directory where the output file will be written string outputDirectory = fileIO.GetDirectoryFromFilePath(options.OutputFilePath); //Indicate to the user that we are retrieving information regarding the input file. This can take a long //time for very large files. DisplayInputFileInfoInProgress(); //Collect information on the input file IntegerFileInfo inputFileInfo = integerFileInfoCollector.GetIntegerFileInfo(options.InputFile, (int)options.ChunkSize); //Store the intermediate files so that they can be deleted later on List <string> intermediateFilePaths = new List <string>(); List <string> chunkFiles = CreateChunkFiles(options, inputFileInfo, outputDirectory); //Translate the file names to file paths var chunkFilePaths = chunkFiles.Select(file => Path.Combine(outputDirectory, file)).ToList(); intermediateFilePaths.AddRange(chunkFilePaths); List <string> mergeIntermediateFilePaths = MergeChunkFiles(chunkFiles, options, inputFileInfo); intermediateFilePaths.AddRange(mergeIntermediateFilePaths); return(intermediateFilePaths); }
/// <summary> /// Creates the chunk files /// </summary> /// <param name="options">The command line options</param> /// <param name="inputFileInfo">Information regarding the input file</param> /// <param name="outputDirectory">The directory where the chunk files will be written</param> /// <returns>The chunk files that were created</returns> private static List <string> CreateChunkFiles(CommandLineOptions options, IntegerFileInfo inputFileInfo, string outputDirectory) { DisplayInputFileInfo(inputFileInfo); //Create the progress bar for the chunk file creation var chunkProgressBar = CreateProgressBar(inputFileInfo.NumOfChunks, ChunkProgressMessage); //Create the progress callback that will be passed to the chunk file creation code Action <int> updateChunkProgress = (int chunkNum) => UpdateProgressBar(chunkProgressBar, chunkNum); //Create the sorted chunk files string chunkFileTemplate = string.Format(GenFileTemplate, "1", "{0}"); List <string> chunkFiles = CreateSortedChunkFiles(options.InputFile, (int)options.ChunkSize, outputDirectory, chunkFileTemplate, updateChunkProgress); if (chunkFiles.Count > 0) { OnProgressBarCompleted(); } DisplayChunkFileCreationResults(chunkFiles.Count); return(chunkFiles); }
/// <summary> /// Displays the integer file information for the input file /// </summary> /// <param name="inputFileInfo">The input file information</param> private static void DisplayInputFileInfo(IntegerFileInfo inputFileInfo) { string integerOutput = "Number of Integers: {0}"; string chunkOutput = "Number of Chunks: {0}"; Console.WriteLine(string.Format(integerOutput, inputFileInfo.NumOfIntegers)); Console.WriteLine(string.Format(chunkOutput, inputFileInfo.NumOfChunks)); }
/// <summary> /// Merges a set of chunk files into a single output file /// </summary> /// <param name="chunkFiles">The chunk files to be merged</param> /// <param name="options">The command line options</param> /// <param name="inputFileInfo">Information regarding the input file</param> /// <returns>The intermediate files that were created while merging</returns> private static List <string> MergeChunkFiles(List <string> chunkFiles, CommandLineOptions options, IntegerFileInfo inputFileInfo) { List <string> intermediateFilePaths = new List <string>(); IFileIO fileIO = serviceProvider.GetService <IFileIO>(); IChunkFileMerger chunkFileMerger = serviceProvider.GetService <IChunkFileMerger>(); //Find the output directory where the output file will be written string outputDirectory = fileIO.GetDirectoryFromFilePath(options.OutputFilePath); //Convert the chunk file names into chunk file paths List <string> chunkFilePaths = chunkFiles .Select(chunkFileName => Path.Combine(outputDirectory, chunkFileName)) .ToList(); //Keep a dictionary of progress bars where the key is the merge generation number, and //the value is the progress bar for that merge generation Dictionary <int, ProgressBar> mergeProgressBars = new Dictionary <int, ProgressBar>(); Action <int, int> updateMergeProgress = (int gen, int integersProcessed) => { if (!mergeProgressBars.ContainsKey(gen)) { //Create a progress bar for the current generation mergeProgressBars[gen] = CreateProgressBar(inputFileInfo.NumOfIntegers, string.Format(MergeProgressMessage, gen - 1)); } bool stepsComplete = UpdateProgressBar(mergeProgressBars[gen], integersProcessed); if (stepsComplete) { OnProgressBarCompleted(); //Display the results of the merge operation. We can calculate the number of output //files that will result from each merge generation int mergedFilesCount = CalculateNumberOfGenerationOutputFiles(chunkFiles.Count, MergeCount, gen - FirstMergeGeneration + 1); DisplayGenMergeResults(gen, mergedFilesCount); } }; List <string> mergeFiles = chunkFileMerger.MergeChunkFilesIntoSingleFile(chunkFilePaths, MergeCount, GenFileTemplate, Path.GetFileName(options.OutputFilePath), outputDirectory, FirstMergeGeneration, !options.KeepIntermediate, updateMergeProgress); intermediateFilePaths.AddRange(mergeFiles); return(intermediateFilePaths); }