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