I am using SharpZipLib to zip up a folder with subdirectories and this is working fine. What I would like to do is strip off the parents directories of the first child file so the whole structure that is irrelevant isn't carried forth...
Example:
c:\a\b\c\d\e\f\g\h\file1.txt
c:\a\b\c\d\e\f\g\h\file2.txt
c:\a\b\c\d\e\f\g\h\i\file1.txt
c:\a\b\c\d\e\f\g\h\i\file2.txt
It should end up like this:
file1.txt
file2.txt
i\file1.txt
i\file2.txt
How can I do this?
Here is the code I have so far:
ZipFile zipFile = new ZipFile(destinationArchive);
zipFile.BeginUpdate();
foreach (FileInfo file in sourceFiles)
{
zipFile.Add(file.FullName);
}
zipFile.CommitUpdate();
zipFile.Close();
Use ZipOutputStream instead:
string[] sourceFiles = new [] { #"c:\a\b\c\d\e\f\g\h\file1.txt", #"c:\a\b\c\d\e\f\g\h\i\file1.txt" };
FileStream fileStream = File.Create(#"c:\temp\test.zip");
ZipOutputStream zipOut = new ZipOutputStream(fileStream);
string baseDir = #"c:\a\b\c\d\e\f\g\h\";
foreach (var sourceFile in sourceFiles)
{
ZipEntry entry = new ZipEntry(sourceFile.Replace(baseDir,""));
zipOut.PutNextEntry(entry);
FileStream inFile = File.OpenRead(sourceFile);
byte[] buffer = new byte[8192];
int bytesRead = 0;
while ((bytesRead = inFile.Read(buffer, 0, buffer.Length)) > 0)
{
zipOut.Write(buffer,0,bytesRead);
}
zipOut.CloseEntry();
}
zipOut.Close();
Or look on CodePlex for DotNetZip.
Related
I need your help, I am new to C#.
I have a program that compress a folder with all its files and folders, but I would like to just compress a specific kind of file.
I use this code to compress:
if (!File.Exists(name_of_zip_folder))
{
ZipFile.CreateFromDirectory(folder, name_of_zip_folder);
}
I would like to do the following:
public void Zipfunction(string folder, List<string> files_to_compress){
//compress these kind of files, keeping the structur of the main folder
}
For example:
Zipfunction(main_folder, new List<string> { "*.xlsx", "*.html"});
How could I compress only specific file types?
This is a code snippet from Jan Welker (Originally posted here) that shows how to compress individual files using SharpZipLib
private static void WriteZipFile(List<string> filesToZip, string path, int compression)
{
if (compression < 0 || compression > 9)
throw new ArgumentException("Invalid compression rate.");
if (!Directory.Exists(new FileInfo(path).Directory.ToString()))
throw new ArgumentException("The Path does not exist.");
foreach (string c in filesToZip)
if (!File.Exists(c))
throw new ArgumentException(string.Format("The File{0}does not exist!", c));
Crc32 crc32 = new Crc32();
ZipOutputStream stream = new ZipOutputStream(File.Create(path));
stream.SetLevel(compression);
for (int i = 0; i < filesToZip.Count; i++)
{
ZipEntry entry = new ZipEntry(Path.GetFileName(filesToZip[i]));
entry.DateTime = DateTime.Now;
using (FileStream fs = File.OpenRead(filesToZip[i]))
{
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
entry.Size = fs.Length;
fs.Close();
crc32.Reset();
crc32.Update(buffer);
entry.Crc = crc32.Value;
stream.PutNextEntry(entry);
stream.Write(buffer, 0, buffer.Length);
}
}
stream.Finish();
stream.Close();
}
Now combinding this with something like this that gets files from a specific folder and you should have what you were asking for if I did not missunderstand your request?
var d = new DirectoryInfo(#"C:\temp");
FileInfo[] Files = d.GetFiles("*.txt"); //Get txt files
List<string> filesToZip = new List<string>();
foreach(FileInfo file in Files )
{
filesToZip.add(file.Name);
}
Hope it helps
//KH.
To create zip archives from a wildcard filtered source you use ZipArchive and manually create a ZipArchiveEntry for any file that meets the specified search criteria. The last page lists a sample that illustrates this. To search in a directory with a wildcard pattern you can use Directory.GetFiles.
With the SharpZip lib I can easily extract a file from a zip archive:
FastZip fz = new FastZip();
string path = "C:/bla.zip";
fz.ExtractZip(bla,"C:/Unzips/",".*");
However this puts the uncompressed folder in the output directory.
Suppose there is a foo.txt file within bla.zip which I want. Is there an easy way to just extract that and place it in the output directory (without the folder)?
The FastZip does not seem to provide a way to change folders, but the "manual" way of doing supports this.
If you take a look at their example:
public void ExtractZipFile(string archiveFilenameIn, string outFolder) {
ZipFile zf = null;
try {
FileStream fs = File.OpenRead(archiveFilenameIn);
zf = new ZipFile(fs);
foreach (ZipEntry zipEntry in zf) {
if (!zipEntry.IsFile) continue; // Ignore directories
String entryFileName = zipEntry.Name;
// to remove the folder from the entry:
// entryFileName = Path.GetFileName(entryFileName);
byte[] buffer = new byte[4096]; // 4K is optimum
Stream zipStream = zf.GetInputStream(zipEntry);
// Manipulate the output filename here as desired.
String fullZipToPath = Path.Combine(outFolder, entryFileName);
string directoryName = Path.GetDirectoryName(fullZipToPath);
if (directoryName.Length > 0)
Directory.CreateDirectory(directoryName);
using (FileStream streamWriter = File.Create(fullZipToPath)) {
StreamUtils.Copy(zipStream, streamWriter, buffer);
}
}
} finally {
if (zf != null) {
zf.IsStreamOwner = true;stream
zf.Close();
}
}
}
As they note, instead of writing:
String entryFileName = zipEntry.Name;
you can write:
String entryFileName = Path.GetFileName(entryFileName)
to remove the folders.
Assuming you know this is the only file (not folder) in the zip:
using(ZipFile zip = new ZipFile(zipStm))
{
foreach(ZipEntry ze in zip)
if(ze.IsFile)//must be our foo.txt
{
using(var fs = new FileStream(#"C:/Unzips/foo.txt", FileMode.OpenOrCreate, FileAccess.Write))
zip.GetInputStream(ze).CopyTo(fs);
break;
}
}
If you need to handle other possibilities, or e.g. getting the name of the zip-entry, the complexity rises accordingly.
I used many existing codes and I tried to zip the folder in many ways but still I am having problem with time and folder size (still approx same size).
this code is from the source of the library and still not giving the wanted result
static void Main(string[] args)
{
//copyDirectory(#"C:\x", #"D:\1");
ZipOutputStream zip = new ZipOutputStream(File.Create(#"d:\2.zip"));
zip.SetLevel(9);
string folder = #"D:\music";
ZipFolder(folder, folder, zip);
zip.Finish();
zip.Close();
}
public static void ZipFolder(string RootFolder, string CurrentFolder, ZipOutputStream zStream)
{
string[] SubFolders = Directory.GetDirectories(CurrentFolder);
foreach (string Folder in SubFolders)
ZipFolder(RootFolder, Folder, zStream);
string relativePath = CurrentFolder.Substring(RootFolder.Length) + "/";
if (relativePath.Length > 1)
{
ZipEntry dirEntry;
dirEntry = new ZipEntry(relativePath);
dirEntry.DateTime = DateTime.Now;
}
foreach (string file in Directory.GetFiles(CurrentFolder))
{
AddFileToZip(zStream, relativePath, file);
}
}
private static void AddFileToZip(ZipOutputStream zStream, string relativePath, string file)
{
byte[] buffer = new byte[4096];
string fileRelativePath = (relativePath.Length > 1 ? relativePath : string.Empty) + Path.GetFileName(file);
ZipEntry entry = new ZipEntry(fileRelativePath);
entry.DateTime = DateTime.Now;
zStream.PutNextEntry(entry);
using (FileStream fs = File.OpenRead(file))
{
int sourceBytes;
do
{
sourceBytes = fs.Read(buffer, 0, buffer.Length);
zStream.Write(buffer, 0, sourceBytes);
} while (sourceBytes > 0);
}
}
string folder = #"D:\music";
If you're trying to zip MP3 files you're not going to see much shrinking.
There are limits to how much a compression algorithm can do anyway. And more compression always takes more time.
I am using ICSharpCode.SharpZipLib.Zip.FastZip to zip files but I'm stuck on a problem:
When I try to zip a file with special characters in its file name, it does not work. It works when there are no special characters in the file name.
I think you cannot use FastZip. You need to iterate the files and add the entries yourself specifying:
entry.IsUnicodeText = true;
To tell SharpZipLib the entry is unicode.
string[] filenames = Directory.GetFiles(sTargetFolderPath);
// Zip up the files - From SharpZipLib Demo Code
using (ZipOutputStream s = new
ZipOutputStream(File.Create("MyZipFile.zip")))
{
s.SetLevel(9); // 0-9, 9 being the highest compression
byte[] buffer = new byte[4096];
foreach (string file in filenames)
{
ZipEntry entry = new ZipEntry(Path.GetFileName(file));
entry.DateTime = DateTime.Now;
entry.IsUnicodeText = true;
s.PutNextEntry(entry);
using (FileStream fs = File.OpenRead(file))
{
int sourceBytes;
do
{
sourceBytes = fs.Read(buffer, 0, buffer.Length);
s.Write(buffer, 0, sourceBytes);
} while (sourceBytes > 0);
}
}
s.Finish();
s.Close();
}
You can continue using FastZip if you would like, but you need to give it a ZipEntryFactory that creates ZipEntrys with IsUnicodeText = true.
var zfe = new ZipEntryFactory { IsUnicodeText = true };
var fz = new FastZip { EntryFactory = zfe };
fz.CreateZip("out.zip", "C:\in", true, null);
You have to download and compile the latest version of SharpZipLib library so you can use
entry.IsUnicodeText = true;
here is your snippet (slightly modified):
FileInfo file = new FileInfo("input.ext");
using(var sw = new FileStream("output.zip", FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
using(var zipStream = new ZipOutputStream(sw))
{
var entry = new ZipEntry(file.Name);
entry.IsUnicodeText = true;
zipStream.PutNextEntry(entry);
using (var reader = new FileStream(file.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = reader.Read(buffer, 0, buffer.Length)) > 0)
{
byte[] actual = new byte[bytesRead];
Buffer.BlockCopy(buffer, 0, actual, 0, bytesRead);
zipStream.Write(actual, 0, actual.Length);
}
}
}
}
Possibility 1: you are passing a filename to the regex file filter.
Possibility 2: those characters are not allowed in zip files (or at least SharpZipLib thinks so)
try to take out the special character from the file name, i,e replace it.
your Filename.Replace("&", "&");
I have somes files in a folder. I want to fetch the files from that folder and convert each file to an object of binary stream and store in a collection. And from the collection, I want to retrieve each binary stream objects. How is it possible using ASP.Net with c# ?
It can be as simply as this:
using System;
using System.Collections.Generic;
using System.IO;
List<FileStream> files = new List<FileStream>();
foreach (string file in Directory.GetFiles("yourPath"))
{
files.Add(new FileStream(file, FileMode.Open, FileAccess.ReadWrite));
}
But overall, storing FileStreams like this does not sound like a good idea and does beg for trouble. Filehandles are a limited resource in any operating system, so hocking them is not very nice nore clever. You would be better off accessing the files as needed instead of simply keeping them open at a whim.
So basically storing only the paths and accessing the files as needed might be a better option.
using System;
using System.Collections.Generic;
using System.IO;
List<String> files = new List<String>();
foreach (string file in Directory.GetFiles("yourPath"))
{
files.Add(file);
}
If you wish to have it stored in a MemoryStream you could try
List<MemoryStream> list = new List<MemoryStream>();
string[] fileNames = Directory.GetFiles("Path");
for (int iFile = 0; iFile < fileNames.Length; iFile++)
{
using (FileStream fs = new FileStream(fileNames[iFile], FileMode.Open))
{
byte[] b = new byte[fs.Length];
fs.Read(b, 0, (int)fs.Length);
list.Add(new MemoryStream(b));
}
}
Or even use a Dictionary if you wish to keep the file names as keys
Dictionary<string, MemoryStream> files = new Dictionary<string, MemoryStream>();
string[] fileNames = Directory.GetFiles("Path");
for (int iFile = 0; iFile < fileNames.Length; iFile++)
{
using (FileStream fs = new FileStream(fileNames[iFile], FileMode.Open))
{
byte[] b = new byte[fs.Length];
fs.Read(b, 0, (int)fs.Length);
files.Add(Path.GetFileName(fileNames[iFile]), new MemoryStream(b));
}
}
This can be done using DirectoryInfo and FileInfo classes. Here is some code that should hopefully do what you need:
System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(#"C:\TempDir\");
if (dir.Exists)
{
foreach (System.IO.FileInfo fi in dir.GetFiles())
{
System.IO.StreamReader sr = new System.IO.StreamReader(fi.OpenRead());
// do what you will....
sr.Close();
}
}