Zip Archive: Can I rename or move a ZipArchiveEntry? - c#

Does the .NET ZipArchive allow to rename or move entries? Currently it's not possible to change the name of a ZipArchiveEntry once it is created. It seems that I have to copy the stream of the original ZipArchiveEntry to a newly ZipArchiveEntry with the changed name.
Thanks
Martin

I don't know what "move" would mean, other than to rename an entry. Even in regular disk file systems, a "move" really is just a rename where the full path of the file name has changed, not just the "leaf node" file name. In a .zip archive, this is even more explicit; a "directory" or "folder" in an archive exists only by virtue of an entry having that directory name in its name (separated, of course, by a directory separator character). So "move" is exactly the same as "rename".
As far as whether you can rename things, no…with ZipArchive, you will have to create a new entry that is a copy of the original, but with the new name, and then delete the original.
Code to do that would look like this:
static void RenameEntry(this ZipArchive archive, string oldName, string newName)
{
ZipArchiveEntry oldEntry = archive.GetEntry(oldName),
newEntry = archive.CreateEntry(newName);
using (Stream oldStream = oldEntry.Open())
using (Stream newStream = newEntry.Open())
{
oldStream.CopyTo(newStream);
}
oldEntry.Delete();
}
Implemented as an extension method, as above, you can call like this:
ZipArchive archive = ...; open archive in "update" mode
string oldName = ...,
newName = ...; // names initialized as appropriate
archive.RenameEntry(oldName, newName);

Related

Stream using behavior

I got simple code, which basically copies file from one dir to another.
string fileName = "kur.csv";
var path = #"D:\" + fileName;
Stream stream = File.OpenRead(fileName);
using Stream s = File.Create(path); // remove "using" from this line
stream.CopyTo(s);
But if I remove "using" (from 4th line start) - code doesn't work on *.csv or *.txt files. But works on *.jpg, *.docx files.
Why it works on some and why it doesn't work on others?
If I had to write a method that copies a file, I'd do something like this:
static void CopyFile(string fileName)
{
var scourceFilePath = Path.Combine(#"D:", fileName);
var destinationFilePath = Path.Combine(#"D:", "destination", fileName);
File.Copy(scourceFilePath, destinationFilePath);
}
This works for all filetypes. You could also check if the directory exists (Directory.Exists(directoryPath)) before referencing it which prevents the program from crashing if the directory does in fact not exist.
I use Path.Combine since by using it I don't have to keep track of the backslashes used.
Every method I mentioned and used is contained in the System.IO namespace.
I hope, that's what you were looking for.

Get the filename of a file that was created through ZipFile.ExtractToDirectory()

string zipPath = #"D:\books\"+fileinfo.DccFileName;
string extractPath = #"D:\books";
System.IO.Compression.ZipFile.ExtractToDirectory(zipPath, extractPath);
This is a simple piece of code that does exactly what i want it to do: Gets a zip file from d:\books and unzips it into the same directory. Is there any way i can read the filename of the newly created file (considering that there is only one file in the .zip archive). I would prefer a solution that does not involve reading changes in the directory since other files might be created in it at the same time of the unzip.
You can construct the path by inspecting the archive
var intentedPath = string.Empty;
//open archive
using (var archive = ZipFile.OpenRead(zipPath)) {
//since there is only one entry grab the first
var entry = archive.Entries.First();
//the relative path of the entry in the zip archive
var fileName = entry.FullName;
//intended path once extracted would be
intentedPath = Path.Combine(extractPath, fileName);
}

Enumerate zipped contents of unzipped folder

I am trying to enumerate the zipped folders that are inside an unzipped folder using Directory.GetDirectories(folderPath).
The problem I have is that it does not seem to be finding the zipped folders, when I come to iterate over the string[], it is empty.
Is Directory.GetDirectories() the wrong way to go about this and if so what method serves this purpose?
Filepath example: C:\...\...\daily\daily\{series of zipped folder}
public void CheckZippedDailyFolder(string folderPath)
{
if(folderPath.IsNullOrEmpty())
throw new Exception("Folder path required");
foreach (var folder in Directory.GetDirectories(folderPath))
{
var unzippedFolder = Compression.Unzip(folder + ".zip", folderPath);
using (TextReader reader = File.OpenText(unzippedFolder + #"\" + new DirectoryInfo(folderPath).Name))
{
var csv = new CsvReader(reader);
var field = csv.GetField(0);
Console.WriteLine(field);
}
}
}
GetDirectories is the wrong thing to use. Explorer lies to you; zip files are actually files with an extension .zip, not real directories on the file system level.
Look at:
https://msdn.microsoft.com/en-us/library/system.io.compression.ziparchive.entries%28v=vs.110%29.aspx (ZipArchive.Entries) and/or
https://msdn.microsoft.com/en-us/library/system.io.compression.zipfile%28v=vs.110%29.aspx (ZipFile) to see how to deal with them.

Sevenzip extractFile(String file, Stream stream) method stream parameter. c#

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);
}
}

Streamreader to a relative filepath

I was wondering, if anyone could tell me how to point a StreamReader to a file inside the current working directory of the program.
E.g.: say I have program Prog saved in the directory "C:\ProgDir\". I commit "\ProgDir" to a shared folder. Inside ProgDir is another directory containing files I'd like to import into Prog (e.g. "\ProgDir\TestDir\TestFile.txt") I'd like to make it so that the StreamReader could read those TestFiles, even when the path to the directory has changed;
(E.G., on my computer, the path to the Testfiles is
C:\ProgDir\TestDir\TestFile.txt
but on the other person's computer, the directory is
C:\dev_code\ProgDir\TestDir\TestFile.txt
).
How would I get a StreamReader to be ale to read from TestFile.txt on the other person's computer? (to clarify, the filenames do not change, the only change is the path ProgDir)
I tried the following:
string currentDir = Environment.CurrentDirectory;
DirectoryInfo directory = new DirectoryInfo(currentDir);
FileInfo file = new FileInfo("TestFile.txt");
string fullDirectory = directory.FullName;
string fullFile = file.FullName;
StreamReader sr = new StreamReader(#fullDirectory + fullFile);
( pulled this from : Getting path relative to the current working directory?)
But I'm getting "TestFile does not exist in the current context". Anyone have any idea as to how I should approach this?
Thank you.
Is the Folder "TestDir" always in the executable directory?
if so, try this
string dir =System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().Location);
string file = dir + #"\TestDir\TestFile.txt";
This will give you the path of the exe plus the folder inside it and the textfile
You can use the GetFullPath() method. Try this:
string filePath = System.IO.Path.GetFullPath("TestFile.txt");
StreamReader sr = new StreamReader(filePath);
A few things:
First, FileInfo.FullName gives the absolute path for the file, so you don't need to prepend the full directory path before the file in the StreamReader instance.
Second, FileInfo file = new FileInfo(TestFile.txt); should fail unless you actually have a class called TestFile with a txt property.
Finally, with almost every File method, they use relative paths already. So you SHOULD be able to use the stream reader on JUST the relative path.
Give those few things a try and let us know.
Edit: Here's what you should try:
FileInfo file = new FileInfo("TestFile.txt");
StreamReader sr = new StreamReader(fullFile.FullName);
//OR
StreamReader sr = new StreamReader("TestFile.txt");
However, one thing I noticed is that the TestFile is located in TestDir. If your executable is located in ProgDir as you're stating, then this will still fail because your relative path isn't right.
Try changing it to TestDir\TestFile.txt instead. IE: StreamReader sr = new StreamReader("TestDir\TestFile.txt");
The FileInfo constructor takes a single parameter of type string. Try putting quotes around TestFile.txt.
Change
FileInfo file = new FileInfo(TestFile.txt);
to
FileInfo file = new FileInfo("TestFile.txt");
Unless TestFile is an object with a property named txt of type string, in which case you have to create the object before trying to use it.
The easiest way would be to just use the file name (not the full path) and "TestDir" and give the StreamReader a relative path.
var relativePath = Path.Combine(".","TestDir",fileName);
using (var sr = new StreamReader(relativePath))
{
//...
}
I had a similar issue and resolved it by using this method:
StreamReader sr = File.OpenText(MapPath("~/your_path/filename.txt"))
This could be a good option if you need a more relative path to the file for working with different environments.
You can use path.combine to get the current directory to build and then combine the file path you need
new StreamReader(Path.Combine(Environment.CurrentDirectory, "storage"));
System.IO.Path.GetDirectoryName(new System.Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath)

Categories