I'm creating a game in which a user can create custom content. There are two files associated with each custom creation: an .ogg file and a .xml file. Previously, I had a folder that contained all of the associated files, but I'd like to wrap all the associated files within a .tar file instead.
Using the following code, I can create a .tar archive (with the custom extension ".krs"):
FileInfo[] filesInDirectory = folder.GetFiles();
string tarArchiveName = #"C:\Users\me\Desktop\UserData\songs\songName.krs";
using (Stream targetStream = new GZipOutputStream(File.Create(tarArchiveName)))
using (TarArchive tarArchive = TarArchive.CreateOutputTarArchive(targetStream, TarBuffer.DefaultBlockFactor))
{
foreach (FileInfo file in filesInDirectory)
{
TarEntry entry = TarEntry.CreateEntryFromFile(file.FullName);
tarArchive.WriteEntry(entry, false);
}
}
This doesn't give any errors, but when I open the .krs file as a .tar using 7zip, the the files are buried underneath ALL the parent directories of the original files that were copied to the archive. For example, the path of the "data.xml" file within the .tar file is "C:\Users\me\Desktop\UserData\songs\songName\data.xml".
I want to open the .tar file and there no top-level directory - just the two files. For example the data.xml file within the .tar archive should be simply "data.xml".
I know this is achieveable because I can do it manually using 7zip. How can I do this using the SharpZipLib library in C#? I found this answer that seems to address my problem, but it's written in Python, a language I have no understanding of.
EDIT: I did some more searching and found this answer. I tried the solution, and it took away everything except the first parent directory of the files (".tar : parentFolder\data.xml"). Is it possible to remove that as well to avoid having to do any digging when I extract these files later?
When testing the answer I posted in my edit, I found that when extracting the files, they come out by themselves and do not come in a folder. This is the answer I was looking for.
Related
I ran into a problem with ZipArchiveMode.Update if the zip file contains "directory entries".
I know there is no such thing as directory entry but some tools produce entries with ZipArchiveEntry.Length = 0 and ZipArchiveEntry.Name = "" for directories in the zip file.
The following code now corrupts the zip file:
using (ZipArchive archive = ZipFile.Open(#"D:\TEMP\test.zip", ZipArchiveMode.Update))
{
}
As you can see I do nothing at all except for opening the zip file with ZipArchiveMode.Update and dispose it in the end.
The problem is that the "directory entries" seem to be treated as file entries. So in the output there are new zero byte entries with the directory names.
I still can open the zip file and even extract files per drag&drop. But attempts to extract the zip file result in error messages. Maybe because there are two entries with the same fullname?
My workaround was to avoid ZipArchiveMode.Update and use a temporary MemoryStream. Then iterate over all entries, ignore "directory entries" and only copy the file entries to the stream. This way it worked.
Is this a bug in ZipArchive or are entries for directories just wrong? What if I want to store empty directories in the zip? And as I said: Many tools out there seem to produce such directory entries.
I got the same issue when trying to update a zip file with directory entries, after updating the file the zip file exist (with the new added file) but its corrupted.
What worked for me eventually was adding Nuget reference to DotNetZip and add the file using Ionic.Zip:
using (Ionic.Zip.ZipFile zip = Ionic.Zip.ZipFile.Read(parameters.ObjzfPath))
{
zip.AddEntry("newFileEntry", "newFileContent"); // you can use zip.AddFile("newFile.txt") as well
zip.Save();
}
I have a business scenario where I should allow downloading of the encrypted folders as a ZIP file; meaning that the files within the folder and its subfolders are encrypted. As I perform server side decryption of the files it is necessary first to recreate the same folder structure in a temporary folder as well as to decrypt the files itself and save them into the corresponding folders of the temporary folder.
This part works well; the folder structure in a temporary file gets recreated as it should but the problem comes when I'm trying to create a ZIP file of a temporary folder using System.IO.Compression library.
When you open the ZIP file only the first folder of the structure is created as a folder and the rest of the folders are just being created as extensionless files.
Folder structure as the unzipping application sees it
Code snippet:
//Creating temporary folder where the decrypted files will be extracted
var tempFolderPath = _directory.CreateTemporaryFolder(rootFolderPath);
var serverTempFolderPath = HttpContext.Current.Server.MapPath(tempFolderPath);
//Creating the folder structure
RecursiveFolderCreate(folders, tempFolderPath);
//Decrypting the files and recreating them in the corresponding folders
foreach (var file in files)
{
PrepareFile(file, folderPath, tempFolderPath);
}
//Creating the zip file
string zipFileName = string.Concat(folder.Name, ".zip");
string zipFilePath = System.IO.Path.Combine(rootFolderPath, zipFileName);
string serverZipFilePath = HttpContext.Current.Server.MapPath(zipFilePath);
ZipFile.CreateFromDirectory(serverTempFolderPath, serverZipFilePath, CompressionLevel.Optimal, false);
byte[] zipFile = System.IO.File.ReadAllBytes(serverZipFilePath);
Sorry this isn't a comment, but I don't have enough reputation to comment yet.
Is it possible that an exception is being raised and not handled?
Per the documentation (https://msdn.microsoft.com/en-us/library/hh485721(v=vs.110).aspx/), what you are doing should work. But it has the extra caveat as listed below:
If a file in the directory cannot be added to the archive, the archive is left incomplete and invalid, and the method throws an IOException exception.
I have a folder containing zip files. I want to unzip them. After unzipping them, I have to find if there are any other zip file found inside the directory. If found, I've to unzip them also. The inner level of the presence of zip files are undetermined. How to unzip all the zip files in sub directories.
It sounds like a fundamentally recursive operation. As Tim indicated above, we can't really give specifics without knowing the library you're using (personally, I'm a fan of Ionic's library), but it would go something like this:
Function Unzip(file as File)
zipfile = ZipLibrary.Load(file);
For Each innerfile as File in zipfile.files
If (innerfile.Name.EndsWith(".zip")) Then
Unzip(innerfile);
End If
End For
End Function
Of course, as with any form of recursion like this, you can potentially save on stack space by building a list of files to be unpacked and adding and iterating through it rather than doing the recursive call. You could also potentially use the zip library itself to check whether a file is a valid zip file if you are uncertain whether it will have the correct extension.
I am currently learning C# during my studies and I am writing a small movie database application in it. I know its not good to save pictures (etc) inside the database, especially when adding movie covers that are rather big. But I don't want the files to just get saved in a folder as this creates a mess if more and more movies are added to the list.
Does anyone know a way to store the files in some sort of a container file (like covers.xxx). Then that container contains all covers in one big file, the files can then be retrieved with an address or the name.
Thanks :)
http://dotnetzip.codeplex.com/
Use above library and following code snippet.
using (ZipFile zip = new ZipFile())
{
// add this map file into the "images" directory in the zip archive
zip.AddFile("c:\\images\\personal\\7440-N49th.png", "images");
// add the report into a different directory in the archive
zip.AddFile("c:\\Reports\\2008-Regional-Sales-Report.pdf", "files");
zip.AddFile("ReadMe.txt");
zip.Save("MyZipFile.zip");
}
I can't see why storing the files as binary in the db is necessarily a bad idea.
However if it's definitely out then it sounds like you want a way to store a non-compressed compilation of files - basically a .zip that isn't compressed. You could achieve this for yourself by creating a file that is simply the data of the files you want appended together with some sort of unique header string in between them that you can split on when you read from the file. Ultimately this is simulating a basic file DB so I'm not sure what you'd accomplish but it's an idea.
I'm using SharpZipLib to create a zip file of a directory in a .NET 3.5 project, and I'm creating the archive like that :
fastZip.CreateZip(Server.MapPath(zipToPath), Server.MapPath(zipFromPath), true, null);
And that doesn't set neither files nor folders filters.
The problem is that the outcome zip file only has some of the sub-directories in that directory and not all of them, say the directory I want to compress has 3 sub-directories, the resulting zip file has only one of them.
Any ideas why is this happening?
A couple of possibles:
Permissions - Since you're using Server.MapPath(), I'm assuming this is a website. In a partial-trust environment the website code has very few permissions, and the library may be swallowing any permissions errors that are occurring during the zip process.
Filenames - Could be a problem with filename length, spaces in the filenames, etc, etc. Since you haven't provided any examples (of the file/directory names, there's no way to narrow it down.
After some debugging I've found the problem.
The cause of the issue is that another process is accessing the created zip file during adding files to it, which causes the SharpZipLib process to terminate and throw an exception, leaving the created zip file with only some of the files.
For more please read my How to know which processes is using a file under ASP.NET? question.