How to get single file from zip file? - vb.net

I want to get just one file from .zip file in VB.NET. I don't need to extract all of .zip file, just one file.
I'm working with framework 4.5.

.NET Framework 4.5 has ZipFile class which can do this for you. This code should get you started:
Dim zipPath As String = "Sample.zip"
Using archive = ZipFile.Open(zipPath, ZipArchiveMode.Read)
Dim entry = archive.GetEntry("MyFile.pdf")
Using reader As New BinaryReader(entry.Open())
System.IO.File.WriteAllBytes("MyFile.pdf", ReadAllBytes(reader))
End Using
End Using
ReadAllBytes() is a helper method that fetches all bytes from a binary stream:
Public Shared Function ReadAllBytes(reader As BinaryReader) As Byte()
Const bufferSize As Integer = 4096
Using ms As New MemoryStream()
Dim buffer(bufferSize) As Byte
Dim count As Integer
Do
count = reader.Read(buffer, 0, buffer.Length)
If count > 0 Then ms.Write(buffer, 0, count)
Loop While count <> 0
Return ms.ToArray()
End Using
End Function
Make sure you're using .NET Framework 4.5 or above and that you have included references to System.IO.Compression and System.IO.Compression.FileSystem.

try with this code with the help of DotNetZip
Using zip As ZipFile = ZipFile.Read(ExistingZipFile)
Dim e As ZipEntry = zip("DocumentToFind.txt")
e.Extract(OutputStream)
End Using
otherwise you can use ZipArchiveClass in this way
Using zip As ZipArchive = ZipFile.Open(zipfile, ZipArchiveMode.Read)
Dim file = zip.Entries.Where(Function(x) x.Name = "fileToFind")
If file IsNot Nothing Then
file.ExtractToFile("yourFile")
End If
End Using

This will allow you to read txt files from a zip line by line
Dim zipPath As String = "ZIP FILE LOCATION"
Using zipStream = New FileStream(last_pafx23_open, FileMode.Open)
Using archive = New ZipArchive(zipStream, ZipArchiveMode.Read)
For Each ent In archive.Entries
MsgBox(ent.ToString)
Using stream = ent.Open()
Using reader = New StreamReader(stream)
While Not reader.EndOfStream
MsgBox(reader.ReadLine)
End While
End Using
End Using
Next
End Using
End Using

Skip the BinaryReader w/ ReadAllBytes() helper function, use ExtractToFile() instead:
Imports System.IO.Compression
Using archive = ZipFile.Open("Sample.zip", ZipArchiveMode.Read)
Dim entry = archive.GetEntry("MyFile.pdf")
If entry IsNot Nothing then entry.ExtractToFile("MyFile.pdf")
End Using
Still needs the references to System.IO.Compression and System.IO.Compression.FileSystem, of course.

Related

VB Method to create a zip file for a folder

I am very new to VB programming. I am trying to create a zip file using vb with sub folders in it, that one of the sub folders need not be included in the zip file created.
Private Function Compress(ByVal fileToCompress As FileInfo) As Boolean
Dim _Compress As Boolean
Using originalFileStream As FileStream = fileToCompress.OpenRead()
If (File.GetAttributes(fileToCompress.FullName) And FileAttributes.Hidden) <> FileAttributes.Hidden And fileToCompress.Extension <> ".gz" Then
Using compressedFileStream As FileStream = File.Create(fileToCompress.FullName + ".gz")
Using compressionStream As GZipStream = New GZipStream(compressedFileStream, CompressionMode.Compress)
originalFileStream.CopyTo(compressionStream)
Console.WriteLine("Compressed {0} from {1} to {2} bytes.",
fileToCompress.Name, fileToCompress.Length.ToString(), compressedFileStream.Length.ToString())
End Using
End Using
End If
End Using
_Compress = File.Exists(fileToCompress.FullName + ".gz")
Return _Compress
End Function

How to zip the folders and its sub-folders in vb.net 2.0?

I have folder in the name of Main1. And inside that folders, i have multiple folders. Like
Folders1
Folders2
Folders3
Folders4
Each folders have their own files. My requirement is to zip "Main1" folder including all the sub-folders and their files.
I dont want to use any third part tools. I'm planning to use namespace System.Compression with Gzip. Please guys advice.
ZipFile.CreateFromDirectory() can easily do this for you. Just pass it the path of your Day1 folder and it will zip the entire folder to a zip file. You can iterate over all the Day folders using System.IO.Directory class.
(Just realized that you want to stick to .NET Fx 2.0. There is no direct way of doing this in that version. You must either use 3rd-party lib, which you don't want to, or do low-level stuff).
Edit
If you're really inclined towards doing it by hand, here is a crude way:
Get the list of all directories (recursive) in your Day directory; call it DirList.
Get the list of all files (recursive) in your Day directory; call it FilesList.
Create a Dictionary(Of String, String) and store the name of each file in FilesList and the BASE64 representation of its contents; name as Key, content as Value.
Save the Dictionary to an XML file using .NET's built-in XML serialization.
At the very start of the file, inject the contents of DirList.
Save the file again. (you could do steps 4-6 in a single step too).
Read this file as binary and use GZip to compress the entire content.
Write it to a zip file.
To uncompress this file:
Open the file and use GZip to decompress and get your entire content.
Grab the list of directories from the top and create all recursively.
Read the remaining section in its entirety and use XML Serialization to create your Dictionary object from it.
Iterate through the Dictionary and create files using the Key part and then inject contents into the files by converting their Value from BASE64 back to binary.
Let me know if you have questions about any of these steps.
Edit 2
The following code is compiled against .NET 2.0 and will compress and decompress a directory:
Public Function ZipDirectory(DirPath As String) As Byte()
If Not Directory.Exists(DirPath) Then Return Nothing
Dim Directories = Directory.GetDirectories(DirPath, "*", SearchOption.AllDirectories)
Dim Files = Directory.GetFiles(DirPath, "*", SearchOption.AllDirectories)
Dim X As New XmlDocument
Dim RootNode = X.CreateElement("Content")
Dim DirsNode = X.CreateElement("Directories")
Dim FilesNode = X.CreateElement("Directories")
X.AppendChild(RootNode)
RootNode.AppendChild(DirsNode)
RootNode.AppendChild(FilesNode)
For Each d In Directories
Dim DirNode = X.CreateElement("Directory")
Dim PathAttrib = X.CreateAttribute("Path")
PathAttrib.Value = d.Replace(DirPath & "\", "") 'Create relative paths
DirNode.Attributes.Append(PathAttrib)
DirsNode.AppendChild(DirNode)
Next
For Each f In Files
Dim FileNode = X.CreateElement("File")
Dim PathAttrib = X.CreateAttribute("Path")
PathAttrib.Value = f.Replace(DirPath & "\", "") 'Create relative paths
FileNode.Attributes.Append(PathAttrib)
FileNode.InnerText = Convert.ToBase64String(File.ReadAllBytes(f))
FilesNode.AppendChild(FileNode)
Next
Using Mem As New MemoryStream()
X.Save(Mem)
Dim AllContentsAsByteArray = Mem.ToArray()
Dim CompressedContent = CompressArray(AllContentsAsByteArray)
Return CompressedContent
End Using
End Function
Public Sub UnzipDirectory(compressed() As Byte, outputPath As String)
If Not Directory.Exists(outputPath) Then Directory.CreateDirectory(outputPath)
Dim Uncompressed = DecompressArray(Compressed)
Dim X As New XmlDocument
Using Mem As New MemoryStream(Uncompressed)
X.Load(Mem)
Dim RootNode = X.FirstChild
Dim DirsNode = RootNode.FirstChild
Dim FilesNode = RootNode.FirstChild.NextSibling
For Each ChildDir In DirsNode.ChildNodes
Directory.CreateDirectory(Path.Combine(outputPath, DirectCast(ChildDir, XmlNode).Attributes.Item(0).Value))
Next
For Each ChildFile In FilesNode.ChildNodes
Dim FilePath = Path.Combine(outputPath, DirectCast(ChildFile, XmlNode).Attributes.Item(0).Value)
Dim Content = Convert.FromBase64String(DirectCast(ChildFile, XmlNode).InnerText)
File.WriteAllBytes(FilePath, Content)
Next
End Using
End Sub
Private Function CompressArray(ByVal content() As Byte) As Byte()
Using outFile As New MemoryStream()
Using Compress As New GZipStream(outFile, CompressionMode.Compress)
Compress.Write(content, 0, content.Length)
End Using
Return outFile.ToArray()
End Using
End Function
Private Function DecompressArray(ByVal content() As Byte) As Byte()
Using outFile As New MemoryStream()
Using inFile As New MemoryStream(content)
Using Compress As New GZipStream(inFile, CompressionMode.Decompress)
Dim buffer(1023) As Byte
Dim nRead As Integer
Do
nRead = Compress.Read(buffer, 0, buffer.Length)
outFile.Write(buffer, 0, nRead)
Loop While nRead > 0
End Using
End Using
Return outFile.ToArray()
End Using
End Function
The code should be used like this:
'To zip a directory
Dim Compressed = ZipDirectory("C:\SomeDir")
File.WriteAllBytes("C:\somedir.zip", Compressed)
'To unzip a zipped file
Dim Compressed = File.ReadAllBytes("C:\somedir.zip")
UnzipDirectory(Compressed, "C:\SomeDir2")
Below code is using System.IO.Compression
Example from MSDN site:
Link
Imports System
Imports System.Collections.Generic
imports System.IO
imports System.IO.Compression
Public Class CompressionSnippet
Public Shared Sub Main()
Dim path As String = "test.txt"
' Create the text file if it doesn't already exist.
If Not File.Exists(path) Then
Console.WriteLine("Creating a new test.txt file")
Dim text() As String = {"This is a test text file.", _
"This file will be compressed and written to the disk.", _
"Once the file is written, it can be decompressed", _
"imports various compression tools.", _
"The GZipStream and DeflateStream class use the same", _
"compression algorithms, the primary difference is that", _
"the GZipStream class includes a cyclic redundancy check", _
"that can be useful for detecting data corruption.", _
"One other side note: both the GZipStream and DeflateStream", _
"classes operate on streams as opposed to file-based", _
"compression data is read on a byte-by-byte basis, so it", _
"is not possible to perform multiple passes to determine the", _
"best compression method. Already compressed data can actually", _
"increase in size if compressed with these classes."}
File.WriteAllLines(path, text)
End If
Console.WriteLine("Contents of {0}", path)
Console.WriteLine(File.ReadAllText(path))
CompressFile(path)
Console.WriteLine()
UncompressFile(path + ".gz")
Console.WriteLine()
Console.WriteLine("Contents of {0}", path + ".gz.txt")
Console.WriteLine(File.ReadAllText(path + ".gz.txt"))
End Sub
Public Shared Sub CompressFile(ByVal path As String)
Dim sourceFile As FileStream = File.OpenRead(path)
Dim destinationFile As FileStream = File.Create(path + ".gz")
Dim buffer(sourceFile.Length) As Byte
sourceFile.Read(Buffer, 0, Buffer.Length)
Using output As New GZipStream(destinationFile, _
CompressionMode.Compress)
Console.WriteLine("Compressing {0} to {1}.", sourceFile.Name, _
destinationFile.Name, False)
output.Write(buffer, 0, buffer.Length)
End Using
' Close the files.
sourceFile.Close()
destinationFile.Close()
End Sub
Public Shared Sub UncompressFile(ByVal path As String)
Dim sourceFile As FileStream = File.OpenRead(path)
Dim destinationFile As FileStream = File.Create(path + ".txt")
' Because the uncompressed size of the file is unknown,
' we are imports an arbitrary buffer size.
Dim buffer(4096) As Byte
Dim n As Integer
Using input As New GZipStream(sourceFile, _
CompressionMode.Decompress, False)
Console.WriteLine("Decompressing {0} to {1}.", sourceFile.Name, _
destinationFile.Name)
n = input.Read(buffer, 0, buffer.Length)
destinationFile.Write(buffer, 0, n)
End Using
' Close the files.
sourceFile.Close()
destinationFile.Close()
End Sub
End Class
Truly you would be better off using SharpLibZip

MongoDB C# How to Update GridFS File and metadata?

Need a solution to to see if the grid file exist and then update the file with metadata.
I am using the solution below. but want a better one.
Don't mind having separate Update and Delete methods.
Thanks
Public Class storedXYZ
Property Data As Stream
Property MetaData As storedXYZMetaData
End Class
Public Sub SaveStoredXYZ(storedXYZ As StoredXYZ)
Dim MongoGridFSCreateOptions As New MongoDB.Driver.GridFS.MongoGridFSCreateOptions
Dim qry As IMongoQuery
qry = Query.EQ("metadata.StoredXYZId", BsonValue.Create(storedXYZ.MetaData.StoredXYZ.ToString()))
Dim gridFile As MongoGridFSFileInfo = mdbGridFS.FindOne(qry)
If gridFile IsNot Nothing Then
Dim mongoStream As MongoGridFSStream
MongoGridFSCreateOptions.Metadata = storedXYZ.MetaData.ToBsonDocument
mongoStream = gridFile.OpenWrite()
''Convert MongoStream to MemoryStream
Dim fs As Stream = New MemoryStream()
Dim buffer As Byte() = New Byte(9999) {}
Dim bytesRead As Integer = 0
Do
bytesRead = storedXYZ.Data.Read(buffer, 0, buffer.Length)
mongoStream.Write(buffer, 0, bytesRead)
Loop While bytesRead > 0
mongoStream.Seek(0, SeekOrigin.Begin)
mongoStream.Position = 0
mdbGridFS.SetMetadata(gridFile, storedAXYZ.MetaData.ToBsonDocument)
Else
MongoGridFSCreateOptions.Metadata = storedXYZ.MetaData.ToBsonDocument
Dim fileinfo As MongoGridFSFileInfo
fileinfo = mdbGridFS.Upload(storedXYZ.Data, storedXYZ.MetaData.Name, MongoGridFSCreateOptions)
End If
End Sub
Rather than trying to overwrite the current file why not just fire off a delete command and then re-upload the file and update the document to the old ones Id?
MongoGridFS Upload method gets a new version of the file when you upload a file using an existing file name.
Using OpenWrite with an existing file name updates the file in place. The C# driver is the only driver that allows to update a GridFS file in place.
More information here
You can use fs.files and fs.chnuks collections as any other collection but you have to be careful to keep important for GridFS data untouched.

Put content of fileStream in dataset

I want to read Stream that i get from XtrapivotGrid of DevExpress. I can save it in the computer but what i want is to save it in one of my table in my dataset called dataset1.
For now i have that code who permit to save it the directory Temp:.
Using FS As New IO.FileStream("D:\Temp\qqc.layout", IO.FileMode.Create)
PivotGridControl1.SaveLayoutToStream(FS)
End Using
Dim read As New System.IO.FileStream("D:\Temp\qqc.layout", IO.FileMode.Open, IO.FileAccess.Read)
DataSet1.LayoutMainRapport.ReadXml(read)
DataSet1.AcceptChanges()
read.Close()
The table LayoutMainRapport have 3 columns:
ID(Int)
Name(nvarchar(50))
Content(xml).
The output from the stream is xml.
thanks in advance!
I believe you should convert your saved layout into string and then save this string to database (and of course you can load this layout back from the database string value):
Private Function SaveLayoutToString(ByVal dxControl As DevExpressControl) As String
Using ms As MemoryStream = New MemoryStream()
dxControl.SaveLayoutToStream(ms)
Return Convert.ToBase64String(ms.ToArray())
End Using
End Function
Private Sub RestoreLayoutFromString(ByVal dxControl As DevExpressControl, ByVal layout As String)
If String.IsNullOrEmpty(layout) Then
Return
End If
Using ms As MemoryStream = New MemoryStream(Convert.FromBase64String(layout))
dxControl.RestoreLayoutFromStream(ms)
End Using
End Sub
Here DevExpressControl dxControl is the DevExpress control which supports saving and loading layout (XtraPivotGrid, XtraGrid, XtraLayoutControl etc.)
I simply had to save a name for the xml and after save it into my dataset.
Dim saveDialog As SaveLayout = New SaveLayout
If saveDialog.ShowDialog() = Windows.Forms.DialogResult.OK Then
Dim read As New IO.MemoryStream
PivotGridControl1.SaveLayoutToStream(read)
read.Position = 0
Dim lecteur As New IO.StreamReader(read)
Dim ligne As DataRow = DataSet1.LayoutMainRapport.NewRow()
ligne("Nom") = saveDialog.txtNom.Text
ligne("Contenu") = lecteur.ReadToEnd()
DataSet1.LayoutMainRapport.Rows.Add(ligne)
LayoutMainRapportTableAdapter.Update(DataSet1)
End If

XmlSerialize directly to GZipStream throws magic number exception on Decompression

I am trying to Serialize an object to XML however my object is a generic list containing many records and causes the serializer to consume lots of memory. So I tried to serialize directly to a GZipStream with the following code:
Dim formatter As XmlSerializer = XmlSerializerFactory.GetSerializerForType(_type)
Using _ms As New MemoryStream()
Using gzStream As New GZipStream(_ms, CompressionMode.Compress, True)
_ms.Position = 0
formatter.Serialize(gzStream, obj)
_ms.Position = 0
gzStream.Flush()
gzStream.Close()
End Using
_ms.Position = 0
Dim decompressData() As Byte
Using gzStream As New GZipStream(_ms, CompressionMode.Decompress)
ReDim decompressData(9000 - 1) 'this number doesn't matter, the data in my test sample is small
Dim Len As Integer = gzStream.Read(decompressData, 0, decompressData.Length)
End Using
End Using
However I run into an InvalidDataException The magic number in GZip header is not correct. Make sure you are passing in a GZip stream. when trying to read the data into the decompressData array.
When I Serialize to a separate memory stream first and then compress that stream such as:
Dim formatter As XmlSerializer = XmlSerializerFactory.GetSerializerForType(_type)
Using _ms As New MemoryStream()
Dim uc_fileBytes() As Byte
Dim uc_len As Integer
Using _ms101 As New MemoryStream()
formatter.Serialize(_ms101, obj)
uc_fileBytes = _ms101.GetBuffer()
uc_len = _ms101.Length
End Using
Using gzStream As New GZipStream(_ms, CompressionMode.Compress, True)
_ms.Position = 0
gzStream.Write(uc_fileBytes, 0, uc_len)
gzStream.Flush()
gzStream.Close()
End Using
Dim decompressData() As Byte
Using gzStream As New GZipStream(_ms, CompressionMode.Decompress)
ReDim decompressData(9000 - 1)
Dim Len As Integer = gzStream.Read(decompressData, 0, decompressData.Length)
End Using
End Using
It works fine without error. But why does it fail when I serialize directly to the GZipStream?
The cause of the problem is because the GZipStream behaves differently (obviously) to the MemoryStream when writing to it. It doesn't handle paged writes very well.