/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /********************************************************** * USING NAMESPACES **********************************************************/ using System; using System.IO; using System.Collections.Generic; using ICSharpCode.SharpZipLib.Zip; using ICSharpCode.SharpZipLib.Tar; using ICSharpCode.SharpZipLib.GZip; using ICSharpCode.SharpZipLib.Core; using QuantConnect.Logging; namespace QuantConnect { /******************************************************** * CLASS DEFINITIONS *********************************************************/ /// /// Compression class manages the opening and extraction of compressed files (zip, tar, tar.gz). /// /// QuantConnect's data library is stored in zip format locally on the hard drive. public static class Compression { /******************************************************** * CLASS VARIABLES *********************************************************/ /******************************************************** * CLASS PROPERTIES *********************************************************/ /******************************************************** * CLASS METHODS *********************************************************/ /// /// Create a zip file of the supplied file names and string data source /// /// Output location to save the file. /// File names and data in a dictionary format. /// True on successfully creating the zip file. public static bool ZipData(string zipPath, Dictionary filenamesAndData) { var success = true; var buffer = new byte[4096]; try { //Create our output using (var stream = new ZipOutputStream(File.Create(zipPath))) { foreach (var filename in filenamesAndData.Keys) { //Create the space in the zip file: var entry = new ZipEntry(filename); //Get a Byte[] of the file data: var file = filenamesAndData[filename].GetBytes(); stream.PutNextEntry(entry); using (var ms = new MemoryStream(file)) { int sourceBytes; do { sourceBytes = ms.Read(buffer, 0, buffer.Length); stream.Write(buffer, 0, sourceBytes); } while (sourceBytes > 0); } } // End For Each File. //Close stream: stream.Finish(); stream.Close(); } // End Using } catch (Exception err) { Log.Error("QC.Data.ZipData(): " + err.Message); success = false; } return success; } /// /// Create a zip file of the supplied file names and data using a byte array /// /// Output location to save the file. /// File names and data in a dictionary format. /// True on successfully saving the file public static bool ZipData(string zipPath, Dictionary filenamesAndData) { var success = true; var buffer = new byte[4096]; try { //Create our output using (var stream = new ZipOutputStream(File.Create(zipPath))) { foreach (var filename in filenamesAndData.Keys) { //Create the space in the zip file: var entry = new ZipEntry(filename); //Get a Byte[] of the file data: var file = filenamesAndData[filename]; stream.PutNextEntry(entry); using (var ms = new MemoryStream(file)) { int sourceBytes; do { sourceBytes = ms.Read(buffer, 0, buffer.Length); stream.Write(buffer, 0, sourceBytes); } while (sourceBytes > 0); } } // End For Each File. //Close stream: stream.Finish(); stream.Close(); } // End Using } catch (Exception err) { Log.Error("QC.Data.ZipData(): " + err.Message); success = false; } return success; } /// /// Uncompress zip data byte array into a dictionary string array of filename-contents. /// /// Byte data array of zip compressed information /// Uncompressed dictionary string-sting of files in the zip public static Dictionary UnzipData(byte[] zipData) { // Initialize: var data = new Dictionary(); try { using (var ms = new MemoryStream(zipData)) { //Read out the zipped data into a string, save in array: using (var zipStream = new ZipInputStream(ms)) { while (true) { //Get the next file var entry = zipStream.GetNextEntry(); if (entry != null) { //Read the file into buffer: var buffer = new byte[entry.Size]; zipStream.Read(buffer, 0, (int)entry.Size); //Save into array: data.Add(entry.Name, buffer.GetString()); } else { break; } } } // End Zip Stream. } // End Using Memory Stream } catch (Exception err) { Log.Error("Data.UnzipData(): " + err.Message); } return data; } /// /// Compress a given file and delete the original file. Automatically rename the file to name.zip. /// /// Path of the original file /// Boolean flag to delete the original file after completion /// String path for the new zip file public static string Zip(string textPath, bool deleteOriginal = true) { var zipPath = ""; try { var buffer = new byte[4096]; zipPath = textPath.Replace(".csv", ".zip"); zipPath = zipPath.Replace(".txt", ".zip"); //Open the zip: using (var stream = new ZipOutputStream(File.Create(zipPath))) { //Zip the text file. var entry = new ZipEntry(Path.GetFileName(textPath)); stream.PutNextEntry(entry); using (var fs = File.OpenRead(textPath)) { int sourceBytes; do { sourceBytes = fs.Read(buffer, 0, buffer.Length); stream.Write(buffer, 0, sourceBytes); } while (sourceBytes > 0); } //Close stream: stream.Finish(); stream.Close(); } //Delete the old text file: if (deleteOriginal) File.Delete(textPath); } catch (Exception err) { Log.Error("QC.Data.Zip(): " + err.Message); } return zipPath; } // End Zip: /// /// Unzip a local file and return its contents via streamreader. /// /// Location of the original zip file /// Stream reader of the first file contents in the zip file public static StreamReader Unzip(string filename) { StreamReader reader = null; var ms = new MemoryStream(); try { if (File.Exists(filename)) { try { using (var zip1 = Ionic.Zip.ZipFile.Read(filename)) { var e = zip1[0]; e.Extract(ms); ms.Position = 0; reader = new StreamReader(ms); } } catch (Exception err) { Log.Error("QC.Data.Unzip(1): " + err.Message); if (reader != null) reader.Close(); } } else { Log.Error("Data.UnZip(2): File doesn't exist: " + filename); } } catch (Exception err) { Log.Error("Data.UnZip(3): " + filename + " >> " + err.Message); } return reader; } // End UnZip /// /// Unzip a local file and return its contents via streamreader: /// public static StreamReader UnzipStream(Stream zipstream) { StreamReader reader = null; try { //Initialise: MemoryStream file; //If file exists, open a zip stream for it. using (var zipStream = new ZipInputStream(zipstream)) { //Read the file entry into buffer: var entry = zipStream.GetNextEntry(); var buffer = new byte[entry.Size]; zipStream.Read(buffer, 0, (int)entry.Size); //Load the buffer into a memory stream. file = new MemoryStream(buffer); } //Open the memory stream with a stream reader. reader = new StreamReader(file); } catch (Exception err) { Log.Error("Data.UnZip(): Stream >> " + err.Message); } return reader; } // End UnZip /// /// Unzip a local file and return its contents via streamreader to a local the same location as the ZIP. /// /// Location of the zip on the HD /// List of unzipped file names public static List UnzipToFolder(string zipFile) { //1. Initialize: var files = new List(); var outFolder = zipFile.Substring(0, zipFile.LastIndexOf(Path.DirectorySeparatorChar)); ZipFile zf = null; try { var fs = File.OpenRead(zipFile); zf = new ZipFile(fs); foreach (ZipEntry zipEntry in zf) { //Ignore Directories if (!zipEntry.IsFile) continue; //Remove the folder from the entry var entryFileName = Path.GetFileName(zipEntry.Name); if (entryFileName == null) continue; var buffer = new byte[4096]; // 4K is optimum var zipStream = zf.GetInputStream(zipEntry); // Manipulate the output filename here as desired. var fullZipToPath = Path.Combine(outFolder, entryFileName); //Save the file name for later: files.Add(fullZipToPath); //Log.Trace("Data.UnzipToFolder(): Input File: " + zipFile + ", Output Directory: " + fullZipToPath); //Copy the data in buffer chunks using (var streamWriter = File.Create(fullZipToPath)) { StreamUtils.Copy(zipStream, streamWriter, buffer); } } } finally { if (zf != null) { zf.IsStreamOwner = true; // Makes close also shut the underlying stream zf.Close(); // Ensure we release resources } } return files; } // End UnZip /// /// Extracts all file from a zip archive and copies them to a destination folder. /// /// The source zip file. /// The destination folder to extract the file to. public static void UnTarFiles(string source, string destination) { var inStream = File.OpenRead(source); var tarArchive = TarArchive.CreateInputTarArchive(inStream); tarArchive.ExtractContents(destination); tarArchive.Close(); inStream.Close(); } /// /// Extract tar.gz files to disk /// /// Tar.gz source file /// Location folder to unzip to public static void UnTarGzFiles(string source, string destination) { var inStream = File.OpenRead(source); var gzipStream = new GZipInputStream(inStream); var tarArchive = TarArchive.CreateInputTarArchive(gzipStream); tarArchive.ExtractContents(destination); tarArchive.Close(); gzipStream.Close(); inStream.Close(); } } // End OS Class } // End QC Namespace