Decompressing a zipfile into memory stream - C# - c#

I have written code to store the encoded string of zip file into temp path and now I want to store the encoded zipfile string to memorystream instead of temp path. Can someone please help me how to read the stream and pass it as a string to ZipFile class...I am using DOTNETZIP library to unpack password protested file.
Please see below my code.
string tempPath = Path.GetTempPath();
foreach (ActivityMimeAttachment a in attachments.Entities)
{
if (a.FileName.EndsWith(".zip", StringComparison.OrdinalIgnoreCase))
{
string strcontent = a.Body;
byte[] filecontent = Convert.FromBase64String(strcontent); // unpack the base-64 to a blob
File.WriteAllBytes(tempPath + a.FileName, filecontent); // Working code creates a zip file
string attachmentfile = tempPath + a.FileName;
using (ZipFile zip = new ZipFile(attachmentfile))
{
foreach (ZipEntry entry in zip.Entries)
{
if ((entry.FileName.EndsWith(".xml", StringComparison.OrdinalIgnoreCase)) ||
(entry.FileName.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase)))
{
entry.ExtractWithPassword(tempPath, "password");
FileStream inFile;
byte[] binaryData;
string file = tempPath + entry.FileName;
inFile = new FileStream(file, FileMode.Open, FileAccess.Read);
binaryData = new Byte[inFile.Length];
long bytesRead = inFile.Read(binaryData, 0,
(int)inFile.Length);
inFile.Close();

You'll want to convert your file content to a memory stream (Stream filestream = new MemoryStream(filecontent)) then use ZipFile.Read(fileStream). Then use a StreamReader to get the contents out as a string. So try something like this (note it's untested):
string myString;
byte[] filecontent = Convert.FromBase64String(strcontent);
using (var filestream = new MemoryStream(filecontent))
{
using (ZipFile zip = ZipFile.Read(filestream))
{
foreach (ZipEntry entry in zip.Entries)
{
if ((entry.FileName.EndsWith(".xml", StringComparison.OrdinalIgnoreCase)) ||
(entry.FileName.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase)))
{
using (var ms = new MemoryStream())
{
entry.ExtractWithPassword(ms, "password");
ms.Position = 0;
var sr = new StreamReader(ms);
myString = sr.ReadToEnd();
}
...
If the results should be a base64 string, do this:
entry.ExtractWithPassword(ms, "password");
ms.Position = 0;
myString = Convert.ToBase64String(ms.ToArray());
You may or may not have to reset the stream position, but it's good practice to.
Now you can use the results as a string without having to write to a file first.

Related

C# - Trying to grab and save a pdf into my database

In my C# application, I am trying to make it able to pull a pdf and save it, so that end users can press a button and pull up that pdf while they are in the application. But when I copy the content to the filestream it makes the pdf but it is just blank with nothing from the original pdf. What am I doing wrong?
The pdf's could also have pictures on them, and I don't think the way I'm doing it would allow those to be brought over.
Microsoft.Win32.OpenFileDialog openFileDialog = new Microsoft.Win32.OpenFileDialog();
bool? response = openFileDialog.ShowDialog();
var fileContent = string.Empty;
var filestream = openFileDialog.OpenFile();
using (StreamReader reader = new StreamReader(filestream))
{
fileContent = reader.ReadToEnd();
}
// make folder path
string FolderPath = "ProjectPDFs\\";
string RootPath = "X:\\Vents-US Inventory";
DirectoryInfo FolderDir = new DirectoryInfo(Path.Combine(RootPath, FolderPath));
Directory.CreateDirectory(FolderDir.ToString());
string filePath = "";
string FileName = openFileDialog.SafeFileName;
if (fileContent.Length > 0)
{
filePath = Path.Combine(FolderDir.ToString(), FileName);
using (Stream fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
byte[] bytestream = Encoding.UTF8.GetBytes(fileContent);
Stream stream = new MemoryStream(bytestream);
stream.CopyTo(fileStream);
}
}

Reading and writing binary data from one to another file

I'm reading a binary file and writing to another file in CP 437 format by skipping few lines. But the output file size is increased than the original file and also data is corrupted. Any help to identify the issue.
StreamReader sStreamReader = new StreamReader(#"D:\Denesh\Input.txt");
string AllData = sStreamReader.ReadToEnd();
string[] rows = AllData.Split(",".ToCharArray());
FileStream fileStream = new FileStream(TransLog, FileMode.Open);
StreamReader streamReader = new StreamReader((Stream)fileStream, Encoding.GetEncoding(437));
StreamWriter streamWriter = new StreamWriter(outFile, false);
int num = 0;
int count = 0;
while (!streamReader.EndOfStream)
{
string tlogline = streamReader.ReadLine();
if (rows[count] == Convert.ToString(num))
{
++count;
}
else
{
++num;
streamWriter.WriteLine(tlogline, streamReader.CurrentEncoding);
}
}
fileStream.Close();
streamWriter.Close();
Adding filestream for streamwriter solves the issue. Thanks.

How do I decode an encoded Base64 zip file to a new zip file?

I'm trying to create a zip file out of an encoded base64 string, but I'm stuck at getting the files from the string.
I have been able to create the zip file out of it, but I don't see the file that should be in it.
My code so far:
public static void Main(string[] args)
{
IConfiguration config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", false, true)
.Build();
var fileName = args[0];
var path = $"{config["zipPath"]}\\{fileName}";
byte[] zipBytes = Convert.FromBase64String(args[1]);
using(var memoryStream = new MemoryStream(zipBytes))
{
// without this I can't open my zip file
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
}
using (var fileStream = new FileStream(path, FileMode.Create))
{
memoryStream.Seek(0, SeekOrigin.Begin);
memoryStream.CopyTo(fileStream);
}
}
}
Clarification
The string that I'm decoding is an encoded zip file. I get the Base64 string and I need to decode it and create a zip file that is the same as the original, including the files that were zipped.
Further Clarification
I receive a zip file from a third party. However, I do not receive it as a zip file, I receive it as an encoded Base64 string. The bytes of that zip are encoded to a Base64 string.
What I need to do is to recreate that original zip file, using the Base64 string that I received.
My suggestion is to use the ZipFile method CreateFromDirectory
public static void Main(string[] args)
{
IConfiguration config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", false, true)
.Build();
var fileName = args[0];
var path = $"{config["zipPath"]}\\{fileName}";
string extractPath = #"c:\users\exampleuser\extract";
byte[] zipBytes = Convert.FromBase64String(args[1]);
using(var memoryStream = new MemoryStream(zipBytes))
{
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Read))
{
archive.ExtractToDirectory(extractPath);
}
ZipFile.CreateFromDirectory(extractPath, path);
}
}
It does not matter at all, what kind of file you are getting, because you receive a binary representation and a filename of it. It can be a .JPG, a .VHD virtual disk, a .MDB database, whatever.
So you can omit the memoryStream and theZipArchive, you simply write the binary data to a file with .zip extension:
public static void Main(string[] args)
{
var path = #"c:\temp\fileName2.zip";
byte[] zipBytes = Convert.FromBase64String("UEsDBBQAAAAIAC5YR063vtp6EwEAALcBAAAJAAAAcHJpbWUudHh0ZZDfSsMwFMbvA3mHPoBCkv5Ze5EL1zkVnBPX2QsRmdtxLWuTkmSyvb0nUaogBHLO73x8+U6eRbIcXKuVLbX6BONgJzkl9c36bvaGvcWRFJSsnAFrK7AOjBesLTyatgcFTjJKFq2qtHFHA/N5JbnIEW1OfxETCSU/YAG9zMeuQhsZB48pqG3j5YIl3xYjyXmBMUJ7bYw2ZQPbg386oKuuK3U/dHDyYZeqOwecZpN81JQaV/DZQ3d7HnDbxsBm9wtrbQ64s+QX6IKeAY4GIShPKbmHDyfjPMv8DoMUeD+1+8bJNGZYT7VzupcFQ2nNJYtYxBMhorgosLzk48GxwLHnQTD5L6DkJfzzA7hXSmbwftz7PF9QSwECFAAUAAAACAAuWEdOt77aehMBAAC3AQAACQAAAAAAAAABACAAAAAAAAAAcHJpbWUudHh0UEsFBgAAAAABAAEANwAAADoBAAAAAA==");
using (FileStream fs = new FileStream(path, FileMode.Create))
{
fs.Write(zipBytes,0,zipBytes.Length);
}
}
(I created a base64 String from a .zip before)
var path = #"c:\temp\import.zip";
string base64 = "";
using (FileStream zip = new FileStream(path, FileMode.Open))
{
var zipBytes = new byte[zip.Length];
zip.Read(zipBytes,0,(int)zip.Length);
base64 = Convert.ToBase64String(zipBytes);
}
Read all text from the file:
example:
string text = System.IO.File.ReadAllText(#"C:\demofile.txt");
Then turn the base64 string, from the text file, into bytes
example:
byte[] bytes = Convert.FromBase64String(text);
Then you can write those bytes to a zip file
example:
File.WriteAllBytes(#"C:\demofile_zip.zip", bytes);
If you want to extract in memory just load it into a memorystream
example:
using (var compressedStream = new MemoryStream(bytes2))
{
using (FileStream decompressedFileStream = File.Create(#"C:\demofile_installer.msi"))
{
using (GZipStream decompressionStream = new GZipStream(compressedStream, CompressionMode.Decompress))
{
decompressionStream.CopyTo(decompressedFileStream);
}
}
}

How to generate a zip with a dat file and a txt file with C#

I need to create a file txt and a file with extension dat. After that I want to compress these files into a zip file and to download it.
My problem is that I don't want to save the files before download. So, can I create and download the zip without creating files on server?
I used MemoryStream. Below you can find the code:
public ZipOutputStream CreateZip(MemoryStream memoryStreamControlFile, MemoryStream memoryStreamDataFile)
{
using (var outputMemStream = new MemoryStream())
{
using (var zipStream = new ZipOutputStream(baseOutputStream))
{
zipStream.SetLevel(3); // 0-9, 9 being the highest level of compression
byte[] bytes = null;
// .dat
var nameFileData = CreateFileName("dat");
var newEntry = new ZipEntry(nameFileData) { DateTime = DateTime.Now };
zipStream.PutNextEntry(newEntry);
bytes = memoryStreamDataFile.ToArray();
var inStream = new MemoryStream(bytes);
StreamUtils.Copy(inStream, zipStream, new byte[4096]);
inStream.Close();
zipStream.CloseEntry();
// .suc
var nameFileControl = CreateFileName("suc");
newEntry = new ZipEntry(nameFileControl) { DateTime = DateTime.Now };
zipStream.PutNextEntry(newEntry);
bytes = memoryStreamControlFile.ToArray();
inStream = new MemoryStream(bytes);
StreamUtils.Copy(inStream, zipStream, new byte[4096]);
inStream.Close();
zipStream.CloseEntry();
// .zip
zipStream.IsStreamOwner = false;
zipStream.Close();
outputMemStream.Position = 0;
return zipStream;
}
}
}
I assume you are working with ASP.Net ?
You can put the file contents (stream, etc...) in a byte array, then output that directly to the user in the response, like :
string fileType = "...zip...";
byte[] fileContent = <your file content> as byte[];
int fileSize = 1000;
string fileName = "filename.zip";
Response.AddHeader("Content-Disposition", "attachment;filename=\"" + fileName + "\"");
Response.ContentType = fileType;
Response.OutputStream.Write(fileContent, 0, fileSize);

Create and write to a text file inmemory and convert to byte array in one go

How can I create a .csv file implicitly/automatically by using the correct method, add text to that file existing in memory and then convert to in memory data to a byte array?
string path = #"C:\test.txt";
File.WriteAllLines(path, GetLines());
byte[] bytes = System.IO.File.ReadAllBytes(path);
With that approach I create a file always (good), write into it (good) then close it (bad) then open the file again from a path and read it from the hard disc (bad)
How can I improve that?
UPDATE
One nearly good approach would be:
using (var fs = new FileStream(#"C:\test.csv", FileMode.Create, FileAccess.ReadWrite))
{
using (var memoryStream = new MemoryStream())
{
fs.CopyTo(memoryStream );
return memoryStream .ToArray();
}
}
but I am not able to write text into that filestream... just bytes...
UPDATE 2
using (var fs = File.Create(#"C:\temp\test.csv"))
{
using (var sw = new StreamWriter(fs, Encoding.Default))
{
using (var ms = new MemoryStream())
{
String message = "Message is the correct ääüö Pi(\u03a0), and Sigma (\u03a3).";
sw.Write(message);
sw.Flush();
fs.CopyTo(ms);
return ms.ToArray();
}
}
}
The string message is not persisted to the test.csv file. Anyone knows why?
Write text into Memory Stream.
byte[] bytes = null;
using (var ms = new MemoryStream())
{
using(TextWriter tw = new StreamWriter(ms)){
tw.Write("blabla");
tw.Flush();
ms.Position = 0;
bytes = ms.ToArray();
}
}
UPDATE
Use file stream Directly and write to File
using (var fs = new FileStream(#"C:\ed\test.csv", FileMode.Create, FileAccess.ReadWrite))
{
using (TextWriter tw = new StreamWriter(fs))
{
tw.Write("blabla");
tw.Flush();
}
}
You can get a byte array from a string using encoding:
Encoding.ASCII.GetBytes(aString);
Or
Encoding.UTF8.GetBytes(aString);
But I don't know why you would want a csv as bytes. You could load the entire file to a string, add to it and then save it:
string content;
using (var reader = new StreamReader(filename))
{
content = reader.ReadToEnd();
}
content += "x,y,z";
using (var writer = new StreamWriter(filename))
{
writer.Write(content);
}
Update: Create a csv in memory and pass back as bytes:
var stringBuilder = new StringBuilder();
foreach(var line in GetLines())
{
stringBuilder.AppendLine(line);
}
return Encoding.ASCII.GetBytes(stringBuilder.ToString());

Categories

Resources