I'm a new .Net developper and i'm facing an issue while developping an Uploaded Zip File in a document Library.
i need to extract the content of the Zip File uploaded to do some actions on the files contained in it.
So i choosed to use ZipArchive Stream to handle my problem, i can retrieve my SPFile from my DocLib easily and create the stream from it.
But i'm not able to create embedded files from ZipArchiveEntry, i tried the following piece of code ( not a copy/past, i'm not on my dev machine )
foreach(SPFile myFile in mySPFolder.Files)
{
ZipArchive myZip = new ZipArchive(myFile.OpenBinaryStream());
foreach(ZipArchiveEntry subZip in ZipArchive.Entries)
{
SPFile newFile = list.RootFolder.Add("myxml.xml",subZip.Open())
}
}
I'm facing an issue while creating my newFile as it's throwing me a System I/O error, as per my understanding it's maybe due to the fact that the stream returned by the method ZipArchiveEntry.Open() is a deflatestream.
I saw that the file creation can be done with a MemoryStream, but i'm not able to understand how to convert a deflatestream to a memorystream.
I got the solution from another place but..
In order to get a memorystream from a deflatestream you need to use the CopyTo() method from Stream.
public void ExtractLibraryZipFolder(SPWeb web, SPList myList, string FolderPath, SPFile myFile, bool overWrite)
{
ZipArchive myZip = new ZipArchive(myFile.OpenBinaryStream());
foreach (ZipArchiveEntry subZip in myZip.Entries)
{
MemoryStream myMemoryStream = new MemoryStream();
subZip.Open().CopyTo(myMemoryStream);
if (FolderPath != string.Empty)
{
SPFolder theFolder = web.GetFolder("/ImportToolLibrary/");
theFolder.SubFolders[FolderPath].Files.Add(subZip.Name, myMemoryStream);
}
else
{
SPFile myUpload = myList.RootFolder.Files.Add(subZip.Name, myMemoryStream);
}
}
}
Related
I am writing data into text file and using below code,
await using var file = new StreamWriter(filePath);
foreach (var packet in resultPackets)
{
file.WriteLine(JsonConvert.SerializeObject(packet));
}
And I am using below code to zip the file with password protected using `DotNetZip,
using (ZipFile zip = new ZipFile())
{
zip.Password = "password";
zip.AddFile(filePath);
zip.Save(#"C:\tmp\data4.zip");
}
Is there a way to combined both, I want to create a file on the fly as password protected.
I don't
want to create first file with data, t
then create zip file from it
and delete the base file
Is this possible? Thanks!
Okay, so since this is still unanswered, here's a small program that does the job for me:
using (var stream = new MemoryStream())
using (var streamWriter = new StreamWriter(stream))
{
// Insert your code in here, i.e.
//foreach (var packet in resultPackets)
//{
// streamWriter.WriteLine(JsonConvert.SerializeObject(packet));
//}
// ... instead I write a simple string.
streamWriter.Write("Hello World!");
// Make sure the contents from the StreamWriter are actually flushed into the stream, then seek the beginning of the stream.
streamWriter.Flush();
stream.Seek(0, SeekOrigin.Begin);
using (ZipFile zip = new ZipFile())
{
zip.Password = "password";
// Write the contents of the stream into a file that is called "test.txt"
zip.AddEntry("test.txt", stream);
// Save the archive.
zip.Save("test.zip");
}
}
Note how AddEntry does not create any form of temporary file. Instead, when the archive is saved, the contents of the stream are read and put into a compressed file within the archive. However, be aware that the whole content of the file are completely kept in memory before it the archive is written to the disk.
I am using .NET 4.5, and the ZipFile class works great if I am trying to zip up an entire directory with "CreateFromDirectory". However, I only want to zip up one file in the directory. I tried pointing to a specific file (folder\data.txt), but that doesn't work. I considered the ZipArchive class since it has a "CreateEntryFromFile" method, but it seems this only allows you to create an entry into an existing file.
Is there no way to simply zip up one file without creating an empty zipfile (which has its issues) and then using the ZipArchiveExtension's "CreateEntryFromFile" method?
**This is also assuming I am working on a company program which cannot use third-party add-ons at the moment.
example from:http://msdn.microsoft.com/en-us/library/ms404280%28v=vs.110%29.aspx
string startPath = #"c:\example\start";
string zipPath = #"c:\example\result.zip";
string extractPath = #"c:\example\extract";
ZipFile.CreateFromDirectory(startPath, zipPath);
ZipFile.ExtractToDirectory(zipPath, extractPath);
But if startPath were to be #"c:\example\start\myFile.txt;", it would throw an error that the directory is invalid.
Use the CreateEntryFromFile off a an archive and use a file or memory stream:
Using a filestream if you are fine creating the zip file and then adding to it:
using (FileStream fs = new FileStream(#"C:\Temp\output.zip",FileMode.Create))
using (ZipArchive arch = new ZipArchive(fs, ZipArchiveMode.Create))
{
arch.CreateEntryFromFile(#"C:\Temp\data.xml", "data.xml");
}
Or if you need to do everything in memory and write the file once it is done, use a memory stream:
using (MemoryStream ms = new MemoryStream())
using (ZipArchive arch = new ZipArchive(ms, ZipArchiveMode.Create))
{
arch.CreateEntryFromFile(#"C:\Temp\data.xml", "data.xml");
}
Then you can write the MemoryStream to a file.
using (FileStream file = new FileStream("file.bin", FileMode.Create, System.IO.FileAccess.Write)) {
byte[] bytes = new byte[ms.Length];
ms.Read(bytes, 0, (int)ms.Length);
file.Write(bytes, 0, bytes.Length);
ms.Close();
}
Using file (or any) stream:
using (var zip = ZipFile.Open("file.zip", ZipArchiveMode.Create))
{
var entry = zip.CreateEntry("file.txt");
entry.LastWriteTime = DateTimeOffset.Now;
using (var stream= File.OpenRead(#"c:\path\to\file.txt"))
using (var entryStream = entry.Open())
stream.CopyTo(entryStream);
}
or briefer:
// reference System.IO.Compression
using (var zip = ZipFile.Open("file.zip", ZipArchiveMode.Create))
zip.CreateEntryFromFile("file.txt", "file.txt");
make sure you add references to System.IO.Compression
Update
Also, check out the new dotnet API documentation for ZipFile and ZipArchive too. There are a few examples there. There is also a warning about referencing System.IO.Compression.FileSystem to use ZipFile.
To use the ZipFile class, you must reference the
System.IO.Compression.FileSystem assembly in your project.
The simplest way to get this working is to use a temporary folder.
FOR ZIPPING:
Create a temp folder
Move file to folder
Zip folder
Delete folder
FOR UNZIPPING:
Unzip archive
Move file from temp folder to your location
Delete temp folder
In .NET, there are quite a few ways to tackle the problem, for a single file. If you don't want to learn everything there, you can get an abstracted library, like SharpZipLib (long standing open source library), sevenzipsharp (requires 7zip libs underneath) or DotNetZip.
just use following code for compressing a file.
public void Compressfile()
{
string fileName = "Text.txt";
string sourcePath = #"C:\SMSDBBACKUP";
DirectoryInfo di = new DirectoryInfo(sourcePath);
foreach (FileInfo fi in di.GetFiles())
{
//for specific file
if (fi.ToString() == fileName)
{
Compress(fi);
}
}
}
public static void Compress(FileInfo fi)
{
// Get the stream of the source file.
using (FileStream inFile = fi.OpenRead())
{
// Prevent compressing hidden and
// already compressed files.
if ((File.GetAttributes(fi.FullName)
& FileAttributes.Hidden)
!= FileAttributes.Hidden & fi.Extension != ".gz")
{
// Create the compressed file.
using (FileStream outFile =
File.Create(fi.FullName + ".gz"))
{
using (GZipStream Compress =
new GZipStream(outFile,
CompressionMode.Compress))
{
// Copy the source file into
// the compression stream.
inFile.CopyTo(Compress);
Console.WriteLine("Compressed {0} from {1} to {2} bytes.",
fi.Name, fi.Length.ToString(), outFile.Length.ToString());
}
}
}
}
}
}
I am trying to access a file in a .7z file. I know the name of the file in the zip folder and that it exists in the .7z file. Previously I've used the ExtractArchive(templocation) which just dumps all the files into a temporary location. Now I want to be able to grab a specific file without extracting the whole .7z file.
7Zip has a class called the SevenZipExtractor that has a method ExtractFile. I would think that is what I am looking for, but I can't find any decent documentation on it.
What I need clarification on is how to go about getting the Stream parameter passed in correctly.
I am using code like this;
//this grabs the zip file and creates a FileInfo array that hold the .7z file (assume there is only one)
DirectoryInfo directoryInfo = new DirectoryInfo(ApplicationPath);
FileInfo[] zipFile = directoryInfo.GetFiles("*.7z");
//This creates the zipextractor on the zip file I just placed in the zipFile FileInfo array
using (SevenZip.SevenZipExtractor zipExtractor = new SevenZip.SevenZipExtractor(zipFile[0].FullName))
//Here I should be able to use the ExtractFile method, however I don't understand the stream parameter, and I can't find any good documentation on the method itself. What is this method looking for?
{
zipExtractor.ExtractFile("ConfigurationStore.xml", Stream stream);
}
Setup a FileStream that SevenZip can write out to:
DirectoryInfo directoryInfo = new DirectoryInfo(ApplicationPath);
FileInfo[] zipFile = directoryInfo.GetFiles("*.7z");
using (SevenZip.SevenZipExtractor zipExtractor = new SevenZip.SevenZipExtractor(zipFile[0].FullName))
{
using (FileStream fs = new FileStream("", FileMode.Create)) //replace empty string with desired destination
{
zipExtractor.ExtractFile("ConfigurationStore.xml", fs);
}
}
I've been having a bit of a problem lately. I've been trying to extract one zip file into a memory stream and then from that stream, use the updateEntry() method to add it to the destination zip file.
The problem is, when the file in the stream is being put into the destination zip, it works if the file is not already in the zip. If there is a file with the same name, it does not overwrite correctly. It says on the dotnetzip docs that this method will overwrite files that are present in the zip with the same name but it does not seem to work. It will write correctly but when I go to check the zip, the files that are supposed to be overwritten have a compressed byte size of 0 meaning something went wrong.
I'm attaching my code below to show you what I'm doing:
ZipFile zipnew = new ZipFile(forgeFile);
ZipFile zipold = new ZipFile(zFile);
using(zipnew) {
foreach(ZipEntry zenew in zipnew) {
percent = (current / zipnew.Count) * 100;
string flna = zenew.FileName;
var fstream = new MemoryStream();
zenew.Extract(fstream);
fstream.Seek(0, SeekOrigin.Begin);
using(zipold) {
var zn = zipold.UpdateEntry(flna, fstream);
zipold.Save();
fstream.Dispose();
}
current++;
}
zipnew.Dispose();
}
Although it might be a bit slow, I found a solution by manually deleting and adding in the file. I'll leave the code here in case anyone else comes across this problem.
ZipFile zipnew = new ZipFile(forgeFile);
ZipFile zipold = new ZipFile(zFile);
using(zipnew) {
// Loop through each entry in the zip file
foreach(ZipEntry zenew in zipnew) {
string flna = zenew.FileName;
// Create a new memory stream for extracted files
var ms = new MemoryStream();
// Extract entry into the memory stream
zenew.Extract(ms);
ms.Seek(0, SeekOrigin.Begin); // Rewind the memory stream
using(zipold) {
// Remove existing entry first
try {
zipold.RemoveEntry(flna);
zipold.Save();
}
catch (System.Exception ex) {} // Ignore if there is nothing found
// Add in the new entry
var zn = zipold.AddEntry(flna, ms);
zipold.Save(); // Save the zip file with the newly added file
ms.Dispose(); // Dispose of the stream so resources are released
}
}
zipnew.Dispose(); // Close the zip file
}
I have been developing a web application with asp.net and I have smoe question about SharZipLib. I have a file called Template.odt (from Open Office) and this file is a compacted file (like docx) and we have some other files inside it (manifiest, xml, images etc). I need to open this file change a file called content.xml and styles.xml and save in another .odt file and give to my client. But I'm not sure if we can use temporary files, so I was thinking how to do this using MemoryStream.
Look what I got:
protected byte[ GetReport() {
Stream inputStream = File.OpenRead(Server.MapPath("~/Odt/Template.odt"));
var zipInputStream = new ZipInputStream(inputStream);
var outputStream = new MemoryStream();
var zipOutputStream = new ZipOutputStream(outputStream);
ZipEntry entry = zipInputStream.GetNextEntry();
while (entry != null) {
if (entry.Name == "content.xml")
// how change the content ?
else if (entry.Name == "styles.xml")
// how change the content ?
// how to add it or create folders in the output ?
zipOutputStream.Write( ??? );
entry = zipInputStream.GetNextEntry();
}
zipOutputStream.Flush();
return outputStream.ToArray();
}
I'm not sure if it's right but I think it's on the way.
I try to take ExtraData from ZipEntry instance but I got it null, is it normal ?
Can someone help me?
Thank you
An example of how you can update ZIP files in memory can be found here:
http://wiki.sharpdevelop.net/SharpZipLib_Updating.ashx#Updating_a_zip_file_in_memory_1
In your case, you probably have to load content.xml into a XmlDocument or XDocument to modify it - but that depends on what you are trying to change exactly.
As a sidemark: when using streams, make sure you are disposing of them. The easiest way is to wrap the operation in using statement:
using(var inputStream = File.OpenRead(Server.MapPath("~/Odt/Template.odt")))
{
// ...
}
More information on that: http://www.codeproject.com/Articles/6564/Understanding-the-using-statement-in-C