How to decompress .zip files in c# without extracting to new location - c#

How can I decompress (.zip) files without extracting to a new location in the .net framework? Specifically, I'm trying to read a filename.csv.zip into a DataTable.
I'm aware of .extractToDirectory (which is within ZipArchive) but I just want to extract it into an object in c# and I would like to not create a new file.
Hoping to be able to do this w/o third party libraries, but I'll take what I can get.

May be some bugs because I never tested this, but here you go:
List<byte[]> urmom = new List<byte[]>();
using (ZipArchive archive = ZipFile.OpenRead(zipPath))
foreach (ZipArchiveEntry entry in archive.Entries)
using (StreamReader r = new StreamReader(entry.Open()))
urmom.Add(r.ReadToEnd(entry));
Basically you use the ZipArchive's openread class to iterate through each entry. At this point, you can use the streamreader to read each entry. From there you can create a file from the stream and even read the filename if you want to. My code doesn't do this, a bit of laziness on my part.

Keep in mind that a compressed stream might contain multiple files. To resolve this is required to iterate through all entries of zip file in order to retrieve them and treat separately.
The sample bellow converts a sequence of bytes in a list of string where each one is the context of the files included in zipped folder:
public static IEnumerable<string> DecompressToEntriesTextContext(byte[] input)
{
var zipEntriesContext = new List<string>();
using (var compressedStream = new MemoryStream(input))
using (var zip = new ZipArchive(compressedStream, ZipArchiveMode.Read))
{
foreach(var entry in zip.Entries)
{
using (var entryStream = entry.Open())
using (var memoryEntryStream = new MemoryStream())
using (var reader = new StreamReader(memoryEntryStream))
{
entryStream.CopyTo(memoryEntryStream);
memoryEntryStream.Position = 0;
zipEntriesContext.Add(reader.ReadToEnd());
}
}
}
return zipEntriesContext;
}

Related

XML file from ZIP Archive is incomplete in C#

I've work with large XML Files (~1000000 lines, 34mb) that are stored in a ZIP archive. The XML file is used at runtime to store and load app settings and measurements. The gets loadeted with this function:
public static void LoadFile(string path, string name)
{
using (var file = File.OpenRead(path))
{
using (var zip = new ZipArchive(file, ZipArchiveMode.Read))
{
var foundConfigurationFile = zip.Entries.First(x => x.FullName == ConfigurationFileName);
using (var stream = new StreamReader(foundConfigurationFile.Open()))
{
var xmlSerializer = new XmlSerializer(typeof(ProjectConfiguration));
var newObject = xmlSerializer.Deserialize(stream);
CurrentConfiguration = null;
CurrentConfiguration = newObject as ProjectConfiguration;
AddRecentFiles(name, path);
}
}
}
}
This works for most of the time.
However, some files don't get read to the end and i get an error that the file contains non valid XML. I used
foundConfigurationFile.ExtractToFile();
and fount that the readed file stops at line ~800000. But this only happens inside this code. When i open the file via editor everything is there.
It looks like the zip doesnt get loaded correctly, or for that matter, completly.
Am i running in some limitations? Or is there an error in my code i don't find?
The file is saved via:
using (var file = File.OpenWrite(Path.Combine(dirInfo.ToString(), fileName.ToString()) + ".pwe"))
{
var zip = new ZipArchive(file, ZipArchiveMode.Create);
var configurationEntry = zip.CreateEntry(ConfigurationFileName, CompressionLevel.Optimal);
var stream = configurationEntry.Open();
var xmlSerializer = new XmlSerializer(typeof(ProjectConfiguration));
xmlSerializer.Serialize(stream, CurrentConfiguration);
stream.Close();
zip.Dispose();
}
Update:
The problem was the File.OpenWrite() method.
If you try to override a file with this method it will result in a mix between the old file and the new file, if the new file is shorter than the old file.
File.OpenWrite() doenst truncate the old file first as stated in the docs
In order to do it correctly it was neccesary to use the File.Create() method. Because this method truncates the old file first.

convert compress xmldocument as zip and get as byte array

I am building a XmlDocument in memory (I am not writing it to disk). I need to be able to create a zip archive that would contain the Xml file and then get the zip archive as byte array (all of this without actually writing/creating anything on the hard-disk). Is this possible?
I should mention that I am trying to do this in C#.
var buffer = new MemoryStream();
using (buffer)
using (var zip = new ZipArchive(buffer, ZipArchiveMode.Create) )
{
var entry = zip.CreateEntry("content.xml", CompressionLevel.Optimal);
using (var stream = entry.Open())
{
xmlDoc.Save(stream);
}
}
var bytes = buffer.ToArray();

Zip files without inclusion of folders

I'm using System.IO.Compression in order to compress a file into a .zip, below the source code:
using (FileStream zipToOpen = new FileStream(zipName, FileMode.CreateNew)){
using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Update)){
ZipArchiveEntry readmeEntry = archive.CreateEntry(#"C:\Users\soc\myFold\someFile.xml");
}
}
This piece of code works well, but unfortunately in the .zip there's the entire sequence of folders (C: -> Users -> ... -> someFile.xml); can I obtain a final .zip with ONLY the file I need? I know that with other libraries this fact is possible (DotNetZip add files without creating folders), but I would like to know if it were possible do the same with the standard library.
You seem to be under the impression that the file will be added to the archive, which is not the case. CreateEntry merely creates an entry with the specified path and entry name, you still need to write the actual file.
In fact, the code in your question is quite similar to the code in the documentation, so I assume you got it from there?
Anyway, to get only the file name you can use Path.GetFileName and then you can write the actual file content to the zip entry.
var filePath = #"C:\temp\foo.txt";
var zipName = #"C:\temp\foo.zip";
using (FileStream zipToOpen = new FileStream(zipName, FileMode.CreateNew))
{
using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Update))
{
ZipArchiveEntry readmeEntry = archive.CreateEntry(Path.GetFileName(filePath));
using (StreamReader reader = new StreamReader(filePath))
using (StreamWriter writer = new StreamWriter(readmeEntry.Open()))
{
writer.Write(reader.ReadToEnd());
}
}
}
The code above will create an archive with foo.txt in the root and with the content of the source file, without any additional directories.

Can I consume a downloaded dbf file without persisting it to disk first?

I'm attempting to acquire data from a website that comes in the form of a zip folder. Inside the zipped folder, there is a .dbf file that I would like to consume (moving it to an in-memory data structure that I can do things with) without persisting it to disk first. If it is possible, I want to do this because I plan to have this code live in an Azure WebJob.
Here is what I'm working with so far:
using (var webClient = new WebClient())
{
var data = webClient.DownloadData(url);
using (var stream = new MemoryStream(data))
using (var archive = new ZipArchive(stream))
{
foreach (var archiveEntry in archive.Entries.Where(entry =>
Path.GetExtension(entry.FullName) == ".dbf"))
{
using (var entryStream = archiveEntry.Open())
{
// TODO: I know how to use an OleDbConnection to
// a file on disk, but I don't plan
// on having a filesystem to persist to...
}
}
}
}
Is this possible? Are there alternatives?

Rename File in IsolatedStorage

I need to rename a file in the IsolatedStorage. How can I do that?
There doesn't appear to anyway in native C# to do it (there might be in native Win32, but I don't know).
What you could do is open the existing file and copy it to a new file and delete the old one. It would be slow compared to a move, but it might be only way.
var oldName = "file.old"; var newName = "file.new";
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
using (var readStream = new IsolatedStorageFileStream(oldName, FileMode.Open, store))
using (var writeStream = new IsolatedStorageFileStream(newName, FileMode.Create, store))
using (var reader = new StreamReader(readStream))
using (var writer = new StreamWriter(writeStream))
{
writer.Write(reader.ReadToEnd());
}
In addition to the copy to a new file, then delete the old file method, starting with Silverlight 4 and .NET Framework v4, IsolatedStorageFile exposes MoveFile and MoveDirectory methods.
Perfectly execute this piece of code
string oldName="oldName";
string newName="newName";
var file = await ApplicationData.Current.LocalFolder.GetFileAsync(oldName);
await file.RenameAsync(newName);

Categories