C#: Programmatically create a split zip file - c#

I want to create a zip file from a folder that it around 1.5GB, and have that zip file be split into chunks of 100MB. I've found quite a few threads on this, but nothing has quite worked out for me.
First I tried System.IO.Compression, but found that it doesn't support splitting the zip files (please correct me if I'm wrong!).
Next I tried Ionic.zip, which looked super easy, but every set of files I create is corrupted in some way (for example, the following code that uses the fonts directory as a test directory creates a set of files that I can't then open or unzip as an archive with either winzip or winrar):
using (var zipFile = new Ionic.Zip.ZipFile(Encoding.UTF8))
{
zipFile.AddDirectory("c:\\windows\\fonts", directoryPathInArchive: string.Empty);
zipFile.MaxOutputSegmentSize = 100 * 1000000;
zipFile.Save("c:\\users\\me\\test.zip");
}
Finally, I've tried the 7z.dll and SharpCompress. Using the Command Line and the 7z.exe file, the following works perfectly:
7z.exe a "c:\users\me\test.zip" "c:\Windows\Fonts" -v100m
But the following code gives the error "Value does not fall within the expected range."
SevenZipCompressor.SetLibraryPath("c:\\program files\\7-zip\\7z.dll");
var compressor = new SevenZipCompressor();
compressor.CompressionMethod = CompressionMethod.Lzma2;
compressor.CustomParameters.Add("v", "100m");
compressor.CompressDirectory("c:\\windows\\fonts\\", "c:\\users\\me\\test.zip");
I've also tried the following (having tried to figure out how the command line switches work in SharpCompress) which does create a zip file, but doesn't split it up:
SevenZipCompressor.SetLibraryPath("c:\\program files\\7-zip\\7z.dll");
var compressor = new SevenZipCompressor();
compressor.CompressionMethod = CompressionMethod.Lzma2;
compressor.CustomParameters.Add("mt", "on");
compressor.CustomParameters.Add("0", "LZMA2:c=100m");
compressor.CompressDirectory("c:\\windows\\fonts\\", "c:\\users\\me\\test.zip");
Does anyone know why any of the above methods aren't working? Or are there any other ways that people have got working that I haven't tried yet?
Thanks!

I am not aware of a library that supports the PKZIP split zip file format.

It's an old question, but Ionic is working. Maybe a little bit tricky, but ok. My first version also creates a set of files that I can't then unzip. But after changing the order of commands, the output can be unzipped.
private static void CreateEncryptedZipFile(string filename, string to, FileInfo fi, string password)
{
using (var zipFile = new Ionic.Zip.ZipFile())
{
zipFile.Password = password;
zipFile.Encryption = Ionic.Zip.EncryptionAlgorithm.WinZipAes256;
zipFile.CompressionLevel = Ionic.Zlib.CompressionLevel.BestCompression;
zipFile.AddFile(filename, directoryPathInArchive: string.Empty);
zipFile.MaxOutputSegmentSize = 1024*1024*128;
zipFile.Save(to + ".zip");
}
createXMLInfo(fi, to);
}

Related

Getting zip files without full directory path using dotnetzip library

I am trying to download a zip of pdf files without having to go through the full directory path
So when I am downloading the files the user will have to click through the entire path to get to the pdf. I want just the files to download without the entire path.
So I did this:
public ActionResult DownloadStatements(string[] years, string[] months, string[] radio, string[] emails, string acctNum)
{
List<string> manypaths = (List<string>)TempData["temp"];
using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile())
{
zip.AddFiles(manypaths , #"\");
MemoryStream output = new MemoryStream();
zip.Save(output);
return File(output.ToArray(), "application/zip");
}
}
In the line zip.AddFiles(manypaths, #"\") I added the #"\" and that seemed to do the trick. But now at that line of code I am getting an error:
System.ArgumentException: 'An item with the same key has already been added.
None of the files are duplicates as I have checked that. I just don't understand what is going on?
I was thinking about maybe if I added a timestamp to it it might help but can't figure out the proper way to do this in dotnetzip library.

cannot find the path to the resource file c#

firstly apology if this has already been answered and I am duplicating the question. I have tried to find the answer to my issue but have failed and none of the auto-suggestions answers my problem.
I have my main project (XAML) and also a class library project called FileStore for files. The class library project is referenced into the main project and I have images and icon file in the class library project that I can access with no issues in my main project, however, I struggle to get the content of a txt file from the CL project to display in a label on the main project. I get the error: the system could not find the file and from the error, I can see that it is trying to look for a file in the main project bin\debug folder
I tried to follow this previous post which seemed to partly answer my issue but to no avail sadly.
Get relative file path in a class library project that is being referenced by a web project
The txt file Build action is set to: Resource and Copy to Output Directory set to: Copy Always.
As I mentioned I have the FileStore project referenced in my main project and the images work fine.
Below is the code I am using, I have tried different variations such as:
\Resources\textFile.txt and \textFile.txt, still no luck.
'''
public static string ReadFileinClLibr()
{
var buildDir =
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var filePath = buildDir + #"\textFile.txt";
return File.ReadAllText(filePath);
}
'''
For comparition here is the path for the image files that works, but I cannot get it to work with the txt file, as the error reads: the given paths format is not supported..
'''
#"pack://application:,,,/FileStore;component/Resources\textFile.txt"
'''
I want to be able to input the content of the text file from the class library project to the label in the main xaml project.
At the moment compiler keeps looking for this file in a debug folder of the main project, what I want is, for the compiler to look for the txt file in a CL FileStore project
In order to access the file all the time, we have to have the file copied to the debug folder. Right click the file from solution explorer change the properties then try to access the file from the executing assembly location.
StringBuilder bodyContent = new StringBuilder();
string fileName = "myfile.txt";
try
{
string filePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), fileName);
using (StreamReader sr = new StreamReader(filePath))
{
// Read the stream.
bodyContent.Append(sr.ReadToEnd());
}
}
catch(Exception ex)
{
Console.WriteLine(String.Format("{0} # {1}", "Exception while reading the file: " + ex.InnerException.Message, DateTime.Now));
throw ex;
}
Thanks to the post from #Sreekanth Gundlapally I have managed to fix my issues. I have mostly drawn on from the answer provided by #Sreekanth Gundlapally but there is one important bit missing. The string fileName should include any subfolders that the resource file is within in the Class Library Project, for example in my case the folder was named 'Resources' so the code should look like this:
string fileName = #"Resources/myfile.txt";
try
{
string filePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), fileName);
using (StreamReader sr = new StreamReader(filePath))
{
// Read the stream.
bodyContent.Append(sr.ReadToEnd());
}
I have also cleaned and rebuilt solution after which it all worked a charm.
Also a side note, anyone trying this and getting funny characters make sure your file's encoding is set to UTF-8 as this is the default encoding used by StreamReader, otherwise your file content may not be read correctly if it contains signs such as apostrophe.

Contains function doesn't find specific files in sub directories

I created a string array that utilizes the Directory.GetFiles function which populates the array with .cs file extensions from all sub directories in my project. This is fine, however, I was trying to write these files to a text document while excluding specific files from the array such as "AssemblyInfo.cs" and "TemporaryGeneratedFiles_xxx.cs" using the contains method to filter files with these names. For the most part, the large majority of these files were not written to the text document, however, there are a few cases where these files manage to show up within the text document.
I've tried using a foreach statement instead of a for loop. I've tried playing around with the str.flush(), str.close(), directoryNames.Dispose(), and directoryNames.Close() by putting them in different spots of the for loop. I tried nesting the if statements instead of using the && operator. The || operator doesn't work in this situation. I've tried using the entire file name and only bits and pieces of the file name and none of this seems to work. At one point I did manage to remove all file that had "Temporary" in it but the "AssemblyInfo.cs" files still remain. I even made a method to completely remove anything with the word temporary or assembly in its file name but that also failed.
FileStream directoryNames = new FileStream(dirListPath, FileMode.OpenOrCreate);
StreamWriter str = new StreamWriter(directoryNames);
string[] allFiles = Directory.GetFiles(dirPath, "*.cs", SearchOption.AllDirectories);
for (int i = 0; i < allFiles.Length; i++)
{
if ((!allFiles[i].Contains("Temporary")) && (!allFiles[i].Contains("Assembly")))
{
str.Write(allFiles[i] + Environment.NewLine);
}
}
str.Flush();
str.Close();
directoryNames.Dispose();
directoryNames.Close();
No error messages occur but as stated above unexpected files pop up where they shouldn't be. Any help would be greatly appreciated.
Thanks to everyone who posted.
After some testing mjwillis was correct. Instead of overwriting the contents in the text file it kept writing to the top of the file and adding on to the contents that were written previously. Fixed it by adding
using (FileStream clearTextDocument = File.Create(dirListPath)) { }
Before the FileStream DirectoryNames line. Feel free to post another way to clear a text document if it's more attractive than this.
As #steve suggested you code ignores case sensitivity.
Try this one.
var allFiles = Directory.EnumerateFiles(dirPath, "*.cs", SearchOption.AllDirectories)
.Where(file => file.IndexOf("Temporary", StringComparison.InvariantCultureIgnoreCase) < 0
&& file.IndexOf("Assembly", StringComparison.InvariantCultureIgnoreCase) < 0);
File.WriteAllLines(dirListPath, allFiles);
PS: This code makes many changes to your code, but in essence they are same.

C# SharpZipLib extract .TGZ NotSupportedException

I'm new to programming so please be patient.
I am currently developing a small Program in Visual C# 2010 Express, .NET Framework 4.0, which starts a Script on a Linux Machine (what creates the File /tmp/logs.tgz), downloads the File and then I want to extract it. Running the Script and downloading the File via Renci.SshNet works flawlessly.
But when I want to extract it, it gives me an Error "NotSupportedException" my Filepath Format is incorrect (which is not the case, I think?).
I copy and pasted the Code directly from here (Simple full extract from a TGZ (.tar.gz)) and edited it for my Needs:
using System.IO;
using System.IO.Compression;
using ICSharpCode.SharpZipLib.GZip;
using ICSharpCode.SharpZipLib.Tar;
//it executed the Script and created the file on the Linux Machine /tmp/logs.tgz
//now I want to download it
string myTime = DateTime.Now.ToString("yyyyMMdd");
var pathWithEnv = (#"%USERPROFILE%\Desktop\logs" + myTime + ".tgz");
var filePath = Environment.ExpandEnvironmentVariables(pathWithEnv);
string localFile = filePath;
//then downloads /tmp/logs.tgz to ..\Desktop\logs+ myTime +.tgz
//everything great until now. here I want to extract .TGZ:
var pathWithEnv2 = (#"%USERPROFILE%\Desktop\logs" + myTime);
var fileDir = Environment.ExpandEnvironmentVariables(pathWithEnv2);
string localDir = fileDir;
Stream inStream = File.OpenRead(localFile);
Stream gzipStream = new GZipInputStream(inStream);
TarArchive tarArchive = TarArchive.CreateInputTarArchive(gzipStream);
//ERROR OCCURS HERE:
tarArchive.ExtractContents(localDir);
tarArchive.Close();
gzipStream.Close();
inStream.Close();
I even tried to set the localFile and localDir string without the EnviromentVariable, but that didnt help. I tried:
- download and extract it directly on C:\ (or on a mapped Network Drive U:) to prevent too long filenames (which should not be the case as it should never get longer than 86 characters).
- string = #"C:..\logs", string = "C:\..\logs", string = #"C:..\logs\", etc.
- tried it without myTime
- using ICSharpCode.SharpZipLib.Core;
I did a MessageBox.Show(localDir); before the tarArchive.ExtractContents(localDir); and it showed "C:\Users\Baumann\Desktop\logs20140530" which is correct, thats the Directory I want to extract it to. Even creating the Directory before executing it doesn't help.
I also created a new Project with just one button which should start the Extraction and the same error occurs.
I tried, doing it separately, first extract the GZip and then the .tar, but it also gives me the same Error when extracting the GZip (using ICSharpCode.SharpZipLib.Core; of course).
What drives me even more crazy about it, is, that it starts to extract it, but not everything, before it fails. And always the same Files, whats not clear for me why these and why not the others.
I'm on Windows 8.1, using SharpZipLib 0.86.0.518, downloaded directly from the Website.
Thanks in advance.
well, I finally fixed the Problem. The Linux machine is creating a file which includes the MAC-Adress and since Windows can't handle ":" in a Filename, it crashes.
I am now extracting file by file and checking each file for ":" and replacing it with "_", works flawlessly.

C# Access text file in zip archive

How can I read content of a text file inside a zip archive?
For example I have an archive qwe.zip, and insite it there's a file asd.txt, so how can I read contents of that file?
Is it possible to do without extracting the whole archive? Because it need to be done quick, when user clicks a item in a list, to show description of the archive (it needed for plugin system for another program). So extracting a whole archive isn't the best solution... because it might be few Mb, which will take at least few seconds or even more to extract... while only that single file need to be read.
You could use a library such as SharpZipLib or DotNetZip to unzip the file and fetch the contents of individual files contained inside. This operation could be performed in-memory and you don't need to store the files into a temporary folder.
Unzip to a temp-folder take the file and delete the temp-data
public static void Decompress(string outputDirectory, string zipFile)
{
try
{
if (!File.Exists(zipFile))
throw new FileNotFoundException("Zip file not found.", zipFile);
Package zipPackage = ZipPackage.Open(zipFile, FileMode.Open, FileAccess.Read);
foreach (PackagePart part in zipPackage.GetParts())
{
string targetFile = outputDirectory + "\\" + part.Uri.ToString().TrimStart('/');
using (Stream streamSource = part.GetStream(FileMode.Open, FileAccess.Read))
{
using (Stream streamDestination = File.OpenWrite(targetFile))
{
Byte[] arrBuffer = new byte[10000];
int iRead = streamSource.Read(arrBuffer, 0, arrBuffer.Length);
while (iRead > 0)
{
streamDestination.Write(arrBuffer, 0, iRead);
iRead = streamSource.Read(arrBuffer, 0, arrBuffer.Length);
}
}
}
}
}
catch (Exception)
{
throw;
}
}
Although late in the game and the question is already answered, in hope that this still might be useful for others who find this thread, I would like to add another solution.
Just today I encountered a similar problem when I wanted to check the contents of a ZIP file with C#. Other than NewProger I cannot use a third party library and need to stay within the out-of-the-box .NET classes.
You can use the System.IO.Packaging namespace and use the ZipPackage class. If it is not already included in the assembly, you need to add a reference to WindowsBase.dll.
It seems, however, that this class does not always work with every Zip file. Calling GetParts() may return an empty list although in the QuickWatch window you can find a property called _zipArchive that contains the correct contents.
If this is the case for you, you can use Reflection to get the contents of it.
On geissingert.com you can find a blog article ("Getting a list of files from a ZipPackage") that gives a coding example for this.
SharpZipLib or DotNetZip may still need to get/read the whole .zip file to unzip a file. Actually, there is still method could make you just extract special file from the .zip file without reading the entire .zip file but just reading small segment.
I needed to have insights into Excel files, I did it like so:
using (var zip = ZipFile.Open("ExcelWorkbookWithMacros.xlsm", ZipArchiveMode.Update))
{
var entry = zip.GetEntry("xl/_rels/workbook.xml.rels");
if (entry != null)
{
var tempFile = Path.GetTempFileName();
entry.ExtractToFile(tempFile, true);
var content = File.ReadAllText(tempFile);
[...]
}
}

Categories