Make a .tar.gz archive without folder structure using SharpZipLib - c#

I am trying to .tar.gz a list of files from a folder using SharpZipLib. The problem is no matter how pass the files paths - the result always contains the files paths - and not only the files thems selves. What am i missing here?
string filesFolder = "c:\\testfolder\\test\\";
List<string> filesToZip = new List<string>() { filesFolder +"test1", filesFolder +"test2"};
using (FileStream fs = new FileStream(filesFolder +"myGz.tar.gz" , FileMode.Create, FileAccess.Write, FileShare.None))
using (Stream gzipStream = new GZipOutputStream(fs))
using (TarArchive tarArchive = TarArchive.CreateOutputTarArchive(gzipStream))
{
foreach (string filename in filesToZip )
{
{
TarEntry tarEntry = TarEntry.CreateEntryFromFile(filename);
tarArchive.WriteEntry(tarEntry, false);
}
}
}
what i get is a "myGz.tar.gz" files. When i try to open it with 7.zip - i get the full folders structure in the archive - c:\testfolder\test\, and in it - "test1", "test".
How do i remove the files paths?
Thanks

I had the same problem, and I figured it out just after finding this question.
The key is to set the Name property of the tarEntry, before adding it into the archive.
TarEntry tarEntry = TarEntry.CreateEntryFromFile(filename);
tarEntry.Name = Path.GetFileName(filename);
tarArchive.WriteEntry(tarEntry, false);

Related

Zip created but no files in it

Can someone tell me what's wrong with my code? I want to zip multiple xml into one file yet the result file is always empty.
using (MemoryStream zipStream = new MemoryStream())
{
using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
{
string[] xmls = Directory.GetFiles(#"c:\temp\test", "*.xml");
foreach (string xml in xmls)
{
var file = zip.CreateEntry(xml);
using (var entryStream = file.Open())
using (var streamWriter = new StreamWriter(entryStream))
{
streamWriter.Write(xml);
}
}
}
using (FileStream fs = new FileStream(#"C:\Temp\test.zip", FileMode.Create))
{
zipStream.Position = 0;
zipStream.CopyTo(fs);
}
}
See the remarks in the documentation (emphasis mine):
The entryName string should reflect the relative path of the entry you want to create within the zip archive. There is no restriction on the string you provide. However, if it is not formatted as a relative path, the entry is created, but you may get an exception when you extract the contents of the zip archive. If an entry with the specified path and name already exists in the archive, a second entry is created with the same path and name.
You are using an absolute path here:
var file = zip.CreateEntry(xml);
My guess is that when you try to open the archive, it is failing silently to show the entries.
Change your code to use the names of the files without their path:
var file = zip.CreateEntry(Path.GetFileName(xml));
As a separate issue, notice that you're just writing the name of the file to the ZIP entry, rather than the actual file. I imagine you want something like this instead:
var zipEntry = zip.CreateEntry(Path.GetFileName(xml));
using (var entryStream = file.Open())
{
using var fileStream = File.OpenRead(xml);
fileStream.CopyTo(entryStream);
}

FileStream says it cant find a part of the path

So i have this console app that looks through a folder for files, this folder only has .tiff images and the whole point of the app is convert them all into pdf files and finally merge them, and so I have this foreach cycle
foreach (var path in Directory.GetFiles(#"C:/Users/tferreira/Desktop/TIF_MarcadAgua"))
{
Console.WriteLine(path); // full path
Console.WriteLine(System.IO.Path.GetFileName(path)); // file name
Escrever("A fazer pdf");
imagens.Add(path.ToUpper().Replace("A.TIF", "A.PDF").Replace("A.tif", "A.PDF"));
FazerPdf(path);
if (File.Exists(path.ToUpper().Replace("A.TIF", "B.TIF")))
{
imagens.Add(path.ToUpper().Replace("A.TIF", "B.PDF"));
FazerPdf(path.ToUpper().Replace("A.TIF", "B.TIF"));
}
Escrever("O pdf foi gerado com sucesso. Caminho : " + path.ToUpper().Replace("A.TIF", "A.PDF").Replace("A.tif", "A.PDF"));
Escrever("Vai fazer o merge de todos os pdfs gerados.");
PdfMerge pm = new PdfMerge();
foreach (string imagem in imagens)
{
pm.AddDocument(imagem);
npages++;
}
}
And what is does is run trough the folder getting all the files and storing the path in that var path variable.
But when it´s actually time to make the pdf it gives that error i mentioned up top.
The line the error happens is this the fazerPDF funtion, thats where the pdf is made, since its a filepath error i will only show the error line since it keeps things easy to see.
using (FileStream stream = new FileStream(Path.Replace("TIF", "PDF"), FileMode.Create, FileAccess.Write))
{
// some code
}
Things i know, the images do exist, the folder does exist.
Thanks for the help, if i myself find out what it is ill post a answer.
EDIT:
fazerPDF function
static public void FazerPdf(string Path)
{
string newPath = System.IO.Path.ChangeExtension(Path, ".pdf");
if (!File.Exists(Path.Replace("TIF", "PDF")))
using (FileStream stream = new FileStream(newPath.Replace("TIF", "PDF"), FileMode.Create, FileAccess.Write))
{
The problem seems to be this line:
using (FileStream stream = new FileStream(Path.Replace("TIF", "PDF"), FileMode.Create, FileAccess.Write))
This will replace all instances of "TIF" in Path with "PDF", no matter where they appear. For example:
c:\TIFs\IlikeTIFfiles\MyTIF.TIF
Would become:
c:\PDFs\IlikePDFfiles\MyPDF.PDF
If you simply want to replace the file extension part of the path, you can use Path.ChangeExtension to cut off the old extension and add the new one:
string newPath = System.IO.Path.ChangeExtension(path, ".pdf");
using (FileStream stream = new FileStream(newPath, FileMode.Create, FileAccess.Write))
Taking the example above, #"c:\TIFs\IlikeTIFfiles\MyTIF.TIF" would become #"c:\TIFs\IlikeTIFfiles\MyTIF.pdf"
See it in action.

Extract files from stream containing zip

I am making a GET request using HttpClient to download a zip file from the internet.
I want to extract all the files contained in the zip file without saving the zip file to disk.
Currently, I am able to download and save the zip file to disk, extract its contents and then delete the zip file from disk. This perfectly fine. However, I want to optimize the process.
I found a way to extract the contents directly from the downloaded zip stream but I have to specify the filenames and extensions.
I am not sure how to extract the contents while preserving their original filenames and extensions without me specifying them.
Current Approach:
string requestUri = "https://www.nuget.org/api/v2/package/" + PackageName + "/" + PackageVersion;
HttpResponseMessage response = await client.GetAsync(requestUri);
response.EnsureSuccessStatusCode();
using Stream PackageStream = await response.Content.ReadAsStreamAsync();
SaveStream($"{DownloadPath}.zip", PackageStream);
ZipFile.ExtractToDirectory($"{DownloadPath}.zip", ExtractPath);
File.Delete($"{DownloadPath}.zip");
// Directly extract Zip contents without saving file and without losing filename and extension
using (ZipArchive archive = new ZipArchive(await response.Content.ReadAsStreamAsync()))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
using (Stream stream = entry.Open())
{
using (FileStream file = new FileStream("file.txt", FileMode.Create, FileAccess.Write))
{
stream.CopyTo(file);
}
}
}
}
.NET 4.8
.NET Core 3.1
C# 8.0
Any help in this regards would be appreciated.
Please feel free to comment on alternative approaches or suggestions.
Thank you in advance.
ZipArchiveEntry has a Name and FullName property that can be used to get the names of the files within the archive while preserving their original filenames and extensions
The FullName property contains the relative path, including the subdirectory hierarchy, of an entry in a zip archive. (In contrast, the Name property contains only the name of the entry and does not include the subdirectory hierarchy.)
For example
using (ZipArchive archive = new ZipArchive(await response.Content.ReadAsStreamAsync())) {
foreach (ZipArchiveEntry entry in archive.Entries) {
using (Stream stream = entry.Open()) {
string destination = Path.GetFullPath(Path.Combine(downloadPath, entry.FullName));
var directory = Path.GetDirectoryName(destination);
if (!Directory.Exists(directory))
Directory.CreateDirectory(directory);
using (FileStream file = new FileStream(destination, FileMode.Create, FileAccess.Write)) {
await stream.CopyToAsync(file);
}
}
}
}
will extract the files in the same subdirectory hierarchy as they were stored in the archive while if entry.Name was used, all the files would be extracted to the same location.

How to give an Order to the files included in zip file created with dotnet Zip

I would like to be able to include the file with a given order while creating a zip while using DotNet Zip.
Files don't appear in the sequence they were added to the zip.For now the order appears to be random.
I would like to have the files xyz-Header,xyz-Summary included first and then the rest of the files.
xyz-Header.csv
xyz-Summary.csv
xyz-Male.csv
xyz-Female.csv
xyz and names for other files are programmatically determined but Header and Summary files are always included.
Code Snippet
private MemoryStream GetZip()
{
ZipFile zip = new ZipFile();
List<string, string> files = getFiles();
zip.AddEntry("xyz-Header.csv", getHeader(files ));
zip.AddEntry("xyz-Summary", getSummary(files));
foreach (var x in files)
{
zip.AddEntry("xyz-" + x.Item1 + ".csv", x.Item2);
}
MemoryStream memoryStream = new MemoryStream();
zip.Save(memoryStream);
memoryStream.position = 0;
return memoryStream;
}
I would appreciate any help on this.
There is not reason the files have to be ordered in the zip, you can get the file list and the give it any order you like:
using (ZipFile zip = ZipFile.Read(NameOfExistingZipFile))
{
foreach (ZipEntry e in zip.Order(x => x.FileName))
{
// do your styff e.Extract();
}
}

DotNetZip: How to extract files, but ignoring the path in the zipfile?

Trying to extract files to a given folder ignoring the path in the zipfile but there doesn't seem to be a way.
This seems a fairly basic requirement given all the other good stuff implemented in there.
What am i missing ?
code is -
using (Ionic.Zip.ZipFile zf = Ionic.Zip.ZipFile.Read(zipPath))
{
zf.ExtractAll(appPath);
}
While you can't specify it for a specific call to Extract() or ExtractAll(), the ZipFile class has a FlattenFoldersOnExtract field. When set to true, it flattens all the extracted files into one folder:
var flattenFoldersOnExtract = zip.FlattenFoldersOnExtract;
zip.FlattenFoldersOnExtract = true;
zip.ExtractAll();
zip.FlattenFoldersOnExtract = flattenFoldersOnExtract;
You'll need to remove the directory part of the filename just prior to unzipping...
using (var zf = Ionic.Zip.ZipFile.Read(zipPath))
{
zf.ToList().ForEach(entry =>
{
entry.FileName = System.IO.Path.GetFileName(entry.FileName);
entry.Extract(appPath);
});
}
You can use the overload that takes a stream as a parameter. In this way you have full control of path where the files will be extracted to.
Example:
using (ZipFile zip = new ZipFile(ZipPath))
{
foreach (ZipEntry e in zip)
{
string newPath = Path.Combine(FolderToExtractTo, e.FileName);
if (e.IsDirectory)
{
Directory.CreateDirectory(newPath);
}
else
{
using (FileStream stream = new FileStream(newPath, FileMode.Create))
e.Extract(stream);
}
}
}
That will fail if there are 2 files with equal filenames. For example
files\additionalfiles\file1.txt
temp\file1.txt
First file will be renamed to file1.txt in the zip file and when the second file is trying to be renamed an exception is thrown saying that an item with the same key already exists

Categories

Resources