How can I read content of a text file inside a zip archive?
For example I have an archive qwe.zip, and insite it there's a file asd.txt, so how can I read contents of that file?
Is it possible to do without extracting the whole archive? Because it need to be done quick, when user clicks a item in a list, to show description of the archive (it needed for plugin system for another program). So extracting a whole archive isn't the best solution... because it might be few Mb, which will take at least few seconds or even more to extract... while only that single file need to be read.
You could use a library such as SharpZipLib or DotNetZip to unzip the file and fetch the contents of individual files contained inside. This operation could be performed in-memory and you don't need to store the files into a temporary folder.
Unzip to a temp-folder take the file and delete the temp-data
public static void Decompress(string outputDirectory, string zipFile)
{
try
{
if (!File.Exists(zipFile))
throw new FileNotFoundException("Zip file not found.", zipFile);
Package zipPackage = ZipPackage.Open(zipFile, FileMode.Open, FileAccess.Read);
foreach (PackagePart part in zipPackage.GetParts())
{
string targetFile = outputDirectory + "\\" + part.Uri.ToString().TrimStart('/');
using (Stream streamSource = part.GetStream(FileMode.Open, FileAccess.Read))
{
using (Stream streamDestination = File.OpenWrite(targetFile))
{
Byte[] arrBuffer = new byte[10000];
int iRead = streamSource.Read(arrBuffer, 0, arrBuffer.Length);
while (iRead > 0)
{
streamDestination.Write(arrBuffer, 0, iRead);
iRead = streamSource.Read(arrBuffer, 0, arrBuffer.Length);
}
}
}
}
}
catch (Exception)
{
throw;
}
}
Although late in the game and the question is already answered, in hope that this still might be useful for others who find this thread, I would like to add another solution.
Just today I encountered a similar problem when I wanted to check the contents of a ZIP file with C#. Other than NewProger I cannot use a third party library and need to stay within the out-of-the-box .NET classes.
You can use the System.IO.Packaging namespace and use the ZipPackage class. If it is not already included in the assembly, you need to add a reference to WindowsBase.dll.
It seems, however, that this class does not always work with every Zip file. Calling GetParts() may return an empty list although in the QuickWatch window you can find a property called _zipArchive that contains the correct contents.
If this is the case for you, you can use Reflection to get the contents of it.
On geissingert.com you can find a blog article ("Getting a list of files from a ZipPackage") that gives a coding example for this.
SharpZipLib or DotNetZip may still need to get/read the whole .zip file to unzip a file. Actually, there is still method could make you just extract special file from the .zip file without reading the entire .zip file but just reading small segment.
I needed to have insights into Excel files, I did it like so:
using (var zip = ZipFile.Open("ExcelWorkbookWithMacros.xlsm", ZipArchiveMode.Update))
{
var entry = zip.GetEntry("xl/_rels/workbook.xml.rels");
if (entry != null)
{
var tempFile = Path.GetTempFileName();
entry.ExtractToFile(tempFile, true);
var content = File.ReadAllText(tempFile);
[...]
}
}
Related
I would like to know if it is possible to check the size of the zip file that is being created dynamically, because I am reading a directory and generate a 19 MB zip and I would like two zips instead to be created, one 10MB and the other 9MB. However, when I give a .Length in the zip file inside my loop it says the size is 0. When I finish adding the files it says that is 19MB. Would anyone know how to do this?
I am using only System.IO.Compression to this task.
here is some example to show how I am trying
String FilePath = "D:\Invoices";
string[] oFiles = Directory.GetFiles(FilePath,"*.pdf");
string name = DateTime.Now.Ticks.ToString()+".zip";
using(FileStream archive1 = File.Open(name,FileMode.Create))
{
using(var arch = new ZipArchive(archive1,ZipArchiveMode.Update))
{
for(int i =0; i<oFiles.Length;i++)
{
var fileinf = new FileInfo(oFiles[i]);
arch.CreateEntryFromFile(fileinf.FullName,fileinf.Name);
//here the zip file is always 0
Console.WriteLine(archive1.Length);
}
}
}
//here the zip file is updated
From the documentation:
When you set the mode to Update … The content of the entire archive is held in memory, and no data is written to the underlying file or stream until the archive is disposed.
If you want to be able to read the size of the file as you're adding things, you need to use ZipArchiveMode.Create.
Otherwise, you should use the ZipArchiveEntry.CompressedSize property to monitor how much you've added to the archive.
So what I'm trying to do right now is opening a .Zip file and renaming a file inside it (.NET 4.6.1). I don't think I'm allowed to use third-party libraries since this is a very simple operation (or so I thought, because I couldn't find any MSDN function to rename entries).
I found a couple of ways, but they are nasty. You can extract the file to disk and add it again with a different name, or you can also create a new entry with the new name in the zip, copy the file through a stream, and delete the original entry.
Is there any effective way to do this? I don't mind any ideas at this point. I know that with DotNetZip its only one line but I can't use a third part library.
Thanks a lot for the help!
Using the ZipArchive in System.IO.Compression. Here is an example that adds a .dat extension to every entry in the specified zip file:
private static void RenameZipEntries(string file)
{
using (var archive = new ZipArchive(File.Open(file, FileMode.Open, FileAccess.ReadWrite), ZipArchiveMode.Update))
{
var entries = archive.Entries.ToArray();
foreach (var entry in entries)
{
var newEntry = archive.CreateEntry(entry.Name + ".dat");
using (var a = entry.Open())
using (var b = newEntry.Open())
a.CopyTo(b);
entry.Delete();
}
}
}
Using C#, Framework 2.0
What is the best optimized way for reading contents of a JS and CSS files?
Note that the contents needs to write out at the same time
EDIT:
To be more clear, while loading the page I need to read all my JS file's contents and write out the contents on a page. Finally this page will act as a single JS file and in the same way for CSS files too.
Since here i am requesting to read the contents of a file number of times.
I am looking for the best way to optimize the performance of it while accessing the file.
As far as I know this is the best way to read the contents of a file,
Use File.ReadAllText(filepath) to get the contents of it.
filepath = Server.MapPath(jsFile);
if (File.Exists(filepath))
{
contents = File.ReadAllText(filepath);
Response.Write(contents);
}
Depends on the kind of project, but you can take a look at Bundling & Minification. That way you don't have to reinvent the wheel.
What is the goal? Scan and output? Here's a version that is encoding-safe (ie: does encoding translation when possible)
void ConcatenateAllSafe(StreamWriter output, params string[] files)
{
foreach (var f in files)
{
using(StreamReader rd = new StreamReader(f))
{
string line = null;
while (null != (line = rd.ReadLine()))
{
output.WriteLine(line);
}
}
}
}
// This version will assume everything is sharing the same encoding
void ConcatenateAllUnsafe(Stream output, params string[] files)
{
var data = new byte[1024 * 64];//64k should be enough for anyone
foreach (string f in files)
{
using (Stream inStream = new FileStream(f, FileMode.Open, FileAccess.Read, FileShare.Read))
{
for (int offset = 0,
read; 0 != (read = inStream.Read(data, offset, data.Length)); offset += read)
{
output.Write(data, 0, read);
}
}
}
}
There is already a ToolkitScriptManager, which will bundle, minify & compress all your javascripts into one request. You may try taking a look into this.
I understand your reason to bundle, minify & compress the javascript and CSS into one file, but fails to understand why it has to be done for every requests. You can either,
Use one of the existing Bundling and Minification tool as suggested by CodeMaster in his answer (YUICompressor, Closure Compiler, AJAXminifier). This would bundle the scripts and CSS only once, that too during build time itself and uses that to serve all the requests. To me this is the most effective way to bundle the scripts and reduces the load on server as they are simply static files and not processing is required for bundling them. Also, the scripts can be treated as static files and be cached at clients or loaded from CDN.
Use Toolkit Script Manager approach, where the custom handler would look for the query string, Look in its cache if the combination is present, if not build the output using Florion's answer and cache it for subsequent calls. By this way, you can avoid frequent file reads.
this is my first question on here, so bear with me.
What I'm aiming to do is just create a basic .zip archive in C#. I have tried using the built-in GZipStream class of .NET and have managed to accomplish this, but then I have the problem that I cannot name the file "usercode.zip" without the archived file losing it's extension. Due to constraints I cannot make my program create these files as "usercode.trf.zip", which is the only way I've found of leaving the filename's extension intact inside the archive.
I've tried using a number of other zipping libraries and I can't seem to manage getting them working properly or the way I want it to.
I came upon the SevenZipHelper library that provides some nifty functions to use the LZMA (or 7-zip) library to compress a file.
The code I'm using looks as follows:
//Take the BF file and zip it, using 7ZipHelper
BinaryReader bReader = new BinaryReader(File.Open(pFileName, FileMode.Open));
byte[] InBuf = new byte[Count];
bReader.Read(InBuf, 0, InBuf.Length);
Console.WriteLine("ZIP: read for buffer length:" + InBuf.Length.ToString());
byte[] OutBuf = SevenZip.Compression.LZMA.SevenZipHelper.Compress(InBuf);
FileStream BZipFile = new FileStream(pZipFileName, FileMode.OpenOrCreate, FileAccess.Write);
BZipFile.Seek(0, SeekOrigin.Begin);
BZipFile.Write(OutBuf, 0, OutBuf.Length);
BZipFile.Close();
This creates a compressed file neatly, using the 7-zip algorithm. Problem is I can't guarantee that the clients using this program will have access to 7-zip, so the file has to be in normal zip algorithm. I've gone through the helper- as well as the 7-zip libraries and it seems it is possible to use this library to compress a file with the normal "ZIP" algorithm. I just cannot seem to figure out how to do this. I've noticed properties settings in a few places, but I cannot find any documentation or googling to tell me where to set this.
I realize there's probably better ways to do this and that I'm just missing something, but I can't sit and struggle with such a supposedly easy task forever. Any help would be greatly appreciated.
If you want you can take a look at this library, I've used it before and it's preaty simple to use : dotnetzip
EDIT(example):
using (ZipFile zip = new ZipFile())
{
foreach (String filename in FilesList)
{
Console.WriteLine("Adding {0}...", filename);
ZipEntry e = zip.AddFile(filename,"");
e.Comment = "file " +filename+" added "+DateTime.Now;
}
Console.WriteLine("Done adding files to zip:" + zipName);
zip.Comment = String.Format("This zip archive was created by '{0}' on '{1}'",
System.Net.Dns.GetHostName(), DateTime.Now);
zip.Save(zipName);
Console.WriteLine("Zip made:" + zipName);
}
I have a .tar file containing multiple compressed .gz files. I have no issue itterating through the .tar file creating each .gz file in a destination directory. I'd like to skip writting the .gz all together and just decompress it from the TarEntry/TarArchive? and write its contents on the fly via the .Net native GZipStream. Not even sure this is possible.
Here is my current code that writes each g'zipped file out. Not sure what to modify to get where I need to be.
using (FileStream _fsIn = new FileStream(#"F:\data\abc.tar", FileMode.Open, FileAccess.Read))
{
using (TarInputStream _tarIn = new TarInputStream(_fsIn))
{
TarEntry _tarEntry;
while ((_tarEntry = _tarIn.GetNextEntry()) != null)
{
string _archiveName = _tarEntry.Name;
using (FileStream _outStr = new FileStream(#"F:\data\" + _archiveName, FileMode.Create))
{
_tarIn.CopyEntryContents(_outStr);
}
}
}
}
I'am not sure what you want to do. Maybe you can clarify your aim. The sharpzlib is not that good documented as I Expected to be.
I've iterated through a tar archive and pushed the content of a file into a new Stream, maybe you can use this as a starting point. Have a look at this StackOverflow Article