C# - extract specific directory from ZIP, preserving folder structure - c#

I have a zip archive and the folder structure inside of an archive looks something like this:
+ dirA
- fileA.txt
+ dirB
- fileB.txt
I'm trying to extract the contents of dirA to disk, but while doing so, I'm unable to perserve the folder structure, and instead of
- fileA.txt
+ dirB
- fileB.txt
I get
- fileA.txt
- fileB.txt
Here's my code:
using (ZipArchive archive = ZipFile.OpenRead(archivePath)) // archivePath is path to the zip archive
{
// get the root directory
var root = archive.Entries[0]?.FullName;
if (root == null) {
// quit in a nice way
}
var result = from curr in archive.Entries
where Path.GetDirectoryName(curr.FullName) != root
where !string.IsNullOrEmpty(curr.Name)
select curr;
foreach (ZipArchiveEntry entry in result)
{
string path = Path.Combine(extractPath, entry.Name); // extractPath is somwhere on the disk
entry.ExtractToFile(path);
}
}
I'm pretty positive that's because I use entry.Name instead of entry.FullName in Path.Combine(), but if I were to use FullName, I would have in path that root directory dirA I'm trying not to extract.
So I've hit a wall here, and the only solution I can think of is extracting the whole zip with:
ZipFile.ExtractToDirectory(archivePath, extractPath);
...and then moving the subfolders from dirA to a different location and deleting dirA. Which doesn't seem like the luckiest of ideas.
Any help is much appreciated.

You could just shorten the FullName by the part of the path you dont want:
foreach (ZipArchiveEntry entry in result)
{
var newName = entry.FullName.Substring(root.Length);
string path = Path.Combine(extractPath, newName);
if (!Directory.Exists(path))
Directory.CreateDirectory(Path.GetDirectoryName(path));
entry.ExtractToFile(path);
}

Related

How to move subfolder with files to another directory in asp.net C#

I want to copy and paste sub-folders of source folder ABC To destination folder. But it is not working. Here is my C# code, it work's fine but it copies the whole folder instead of only the sub-folders.
// string fileName = "test.txt";
string sourcePath = "D:\\Shraddha\\Demo_Web_App\\Source";
string targetPath = "D:\\Shraddha\\Demo_Web_App\\Destination";
// Use Path class to manipulate file and directory paths.
string sourceFile = System.IO.Path.Combine(sourcePath);
string destFile = System.IO.Path.Combine(targetPath);
// To copy a folder's contents to a new location:
// Create a new target folder, if necessary.
if (System.IO.Directory.Exists(targetPath))
{
System.IO.Directory.CreateDirectory(targetPath);
}
// To copy a file to another location and
// overwrite the destination file if it already exists.
// System.IO.File.Copy(sourceFile, destFile, true);
// To copy all the files in one directory to another directory.
// Get the files in the source folder. (To recursively iterate through
// all subfolders under the current directory, see
// "How to: Iterate Through a Directory Tree.")
// Note: Check for target path was performed previously
// in this code example.
if (System.IO.Directory.Exists(sourcePath))
{
string[] files = System.IO.Directory.GetFiles(sourcePath);
// Copy the files and overwrite destination files if they already exist.
foreach (string s in files)
{
// Use static Path methods to extract only the file name from the path.
//fileName = System.IO.Path.GetFileName(s);
destFile = System.IO.Path.Combine(targetPath);
System.IO.File.Copy(s, destFile, true);
}
}
else
{
Console.WriteLine("Source path does not exist!");
}
// Keep console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
Alright, here we go:
This doesn't really makes sense. If targetPath exists, create targetPath folder?
if (System.IO.Directory.Exists(targetPath))
{
System.IO.Directory.CreateDirectory(targetPath);
}
You probably meant:
if (!System.IO.Directory.Exists(targetPath))
{
System.IO.Directory.CreateDirectory(targetPath);
}
What you need to do first is, getting all directories to begin with:
var allDirectories = Directory.GetDirectories(targetPath, "*", SearchOption.AllDirectories);
then you can loop through allDirectories with foreach, find all files in each folder and copy the contents.
The following line cannot work like provided:
destFile = System.IO.Path.Combine(targetPath);
File.Copy expects a path to a file where you want to copy the content from "s", but you are providing only the destination folder. You have to include a filename in the Path.Combine method.
If you parse the path strings with the Path.GetFileName method for example, you can pass the result (only the filename without full source path) as an additional argument to Path.Combine to generate a valid destination path.
Additionally, like uteist already said, you have to get all subdirectories first, because in your code example, you're only copying the files, directly placed under your root source folder.
To keep the Directory structure
foreach (var dir in System.IO.Directory.GetDirectories(sourcePath))
{
var dirInfo = new System.IO.DirectoryInfo(dir);
System.IO.Directory.CreateDirectory(System.IO.Path.Combine(targetPath, dirInfo.Name));
foreach (var file in System.IO.Directory.GetFiles(dir))
{
var fileInfo = new System.IO.FileInfo(file);
fileInfo.CopyTo(System.IO.Path.Combine(targetPath, dirInfo.Name, fileInfo.Name));
}
};

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.

Visual C#: Move multiple files with the same extensions into another directory

guys. I've got a problem I can't solve:
I have a 2 folders I choose with folderBrowserDialog and tons of files in source directory I need to move to the target directory. But, I have only to move files with a specific extension like .txt or any other extension I can get from textbox.
So how can I do it?
First get all the files with specified extension using Directory.GetFiles() and then iterate through each files in the list and move them to target directory.
//Assume user types .txt into textbox
string fileExtension = "*" + textbox1.Text;
string[] txtFiles = Directory.GetFiles("Source Path", fileExtension);
foreach (var item in txtFiles)
{
File.Move(item, Path.Combine("Destination Directory", Path.GetFileName(item)));
}
Try this:
For copying files...
foreach (string s in files)
{
File.Copy(s, "C:\newFolder\newFilename.txt");
}
for moving files
foreach (string s in files)
{
File.Move(s, "C:\newFolder\newFilename.txt");
}
Example for Moving files to Directory:
string filepath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
DirectoryInfo d = new DirectoryInfo(filepath);
foreach (var file in d.GetFiles("*.txt"))
{
Directory.Move(file.FullName, filepath + "\\TextFiles\\" + file.Name);
}
will Move all the files from Desktop to Directory "TextFiles".

Moving files from one folder to another C#

Guys I am trying to move all files ending with _DONE into another folder.
I tried
//take all files of main folder to folder model_RCCMrecTransfered
string rootFolderPath = #"F:/model_RCCMREC/";
string destinationPath = #"F:/model_RCCMrecTransfered/";
string filesToDelete = #"*_DONE.wav"; // Only delete WAV files ending by "_DONE" in their filenames
string[] fileList = System.IO.Directory.GetFiles(rootFolderPath, filesToDelete);
foreach (string file in fileList)
{
string fileToMove = rootFolderPath + file;
string moveTo = destinationPath + file;
//moving file
File.Move(fileToMove, moveTo);
But on executing these codes i get an error saying.
The given path's format is not supported.
Where did I go wrong ?
Your slashes are in the wrong direction. On windows you should use back slashes. E.g.
string rootFolderPath = #"F:\model_RCCMREC\";
string destinationPath = #"F:\model_RCCMrecTransfered\";
I made it this way:
if (Directory.Exists(directoryPath))
{
foreach (var file in new DirectoryInfo(directoryPath).GetFiles())
{
file.MoveTo($#"{newDirectoryPath}\{file.Name}");
}
}
file is a type of FileInfo class. It already has a Method called MoveTo() that takes a destination path.
The array of file names returned from System.IO.Directory.GetFiles() includes their full path. (See http://msdn.microsoft.com/en-us/library/07wt70x2.aspx) This means that appending the source and destination directories to the file value isn't going to be what you expect. You'll end up with values like F:\model_RCCMREC\F:\model_RCCMREC\something_DONE.wav in fileToMove. If you set a breakpoint on the File.Move() line, you could look at the values you are passing, which can help debug a situation like this.
Briefly, you'll need to determine the relative path from rootFolderPath to each file in order to determine the proper destination path. Take a look at the System.IO.Path class (http://msdn.microsoft.com/en-us/library/system.io.path.aspx) for methods that will help. (In particular, you should consider Path.Combine() rather than + for building paths.)
Please try the below function. This works fine.
Function:
public static void DirectoryCopy(string strSource, string Copy_dest)
{
DirectoryInfo dirInfo = new DirectoryInfo(strSource);
DirectoryInfo[] directories = dirInfo.GetDirectories();
FileInfo[] files = dirInfo.GetFiles();
foreach (DirectoryInfo tempdir in directories)
{
Console.WriteLine(strSource + "/" +tempdir);
Directory.CreateDirectory(Copy_dest + "/" + tempdir.Name);// creating the Directory
var ext = System.IO.Path.GetExtension(tempdir.Name);
if (System.IO.Path.HasExtension(ext))
{
foreach (FileInfo tempfile in files)
{
tempfile.CopyTo(Path.Combine(strSource + "/" + tempfile.Name, Copy_dest + "/" + tempfile.Name));
}
}
DirectoryCopy(strSource + "/" + tempdir.Name, Copy_dest + "/" + tempdir.Name);
}
FileInfo[] files1 = dirInfo.GetFiles();
foreach (FileInfo tempfile in files1)
{
tempfile.CopyTo(Path.Combine(Copy_dest, tempfile.Name));
}
}

Find all files in a folder

I am looking to create a program that finds all files of a certain type on my desktop and places them into specific folders, for example, I would have all files with .txt into the Text folder.
Any ideas what the best way would be to accomplish this? Thanks.
I have tried this:
string startPath = #"%userprofile%/Desktop";
string[] oDirectories = Directory.GetDirectories(startPath, "");
Console.WriteLine(oDirectories.Length.ToString());
foreach (string oCurrent in oDirectories)
Console.WriteLine(oCurrent);
Console.ReadLine();
It was not successful in finding all of the files.
A lot of these answers won't actually work, having tried them myself. Give this a go:
string filepath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
DirectoryInfo d = new DirectoryInfo(filepath);
foreach (var file in d.GetFiles("*.txt"))
{
Directory.Move(file.FullName, filepath + "\\TextFiles\\" + file.Name);
}
It will move all .txt files on the desktop to the folder TextFiles.
First off; best practice would be to get the users Desktop folder with
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
Then you can find all the files with something like
string[] files = Directory.GetFiles(path, "*.txt", SearchOption.AllDirectories);
Note that with the above line you will find all files with a .txt extension in the Desktop folder of the logged in user AND all subfolders.
Then you could copy or move the files by enumerating the above collection like
// For copying...
foreach (string s in files)
{
File.Copy(s, "C:\newFolder\newFilename.txt");
}
// ... Or for moving
foreach (string s in files)
{
File.Move(s, "C:\newFolder\newFilename.txt");
}
Please note that you will have to include the filename in your Copy() (or Move()) operation. So you would have to find a way to determine the filename of at least the extension you are dealing with and not name all the files the same like what would happen in the above example.
With that in mind you could also check out the DirectoryInfo and FileInfo classes.
These work in similair ways, but you can get information about your path-/filenames, extensions, etc. more easily
Check out these for more info:
http://msdn.microsoft.com/en-us/library/system.io.directory.aspx
http://msdn.microsoft.com/en-us/library/ms143316.aspx
http://msdn.microsoft.com/en-us/library/system.io.file.aspx
You can try with Directory.GetFiles and fix your pattern
string[] files = Directory.GetFiles(#"c:\", "*.txt");
foreach (string file in files)
{
File.Copy(file, "....");
}
Or Move
foreach (string file in files)
{
File.Move(file, "....");
}
http://msdn.microsoft.com/en-us/library/wz42302f

Categories