I have a directory where all kind of random data is in it including ZIP archives which could also include ZIP archives itself and so on. What I want to count is all data except the ZIP archives.
My attempt with starting to count the data in the ZIP files:
static void Main(string[] args)
{
DirectoryInfo directoryInfo = new DirectoryInfo(#"C:\Temp");
int count = 0;
foreach (FileInfo file in directoryInfo.GetFiles())
{
if (file.Extension.Equals(".zip"))
{
count += ZipFileCount(file.FullName);
}
}
Console.WriteLine(count);
}
public static int ZipFileCount(String zipFileName)
{
using (ZipArchive archive = ZipFile.Open(zipFileName, ZipArchiveMode.Read))
{
foreach (var entry in archive.Entries)
{
if (!String.IsNullOrEmpty(entry.Name))
{
count += 1;
if (entry.Name.Substring(entry.Name.Length - 3).Equals("zip"))
{
ZipFileCount(entry.Name);
}
}
}
return count;
}
}
That didn't work out as ZipFileCount(entry.Name) does not provide the right entries in the ZIP of the ZIP.
Anybody can help me out to fix this?
One way of accomplishing it is extracting all the zips to a temporary folder recursively and then count for non-zip files inside of those directories. Once we get the count we can delete the intermediate files and revert the system to initial state. Remember the user needs to have write permissions on the file system to run the code in that particular directory.
using System;
using System.IO;
using System.IO.Compression;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
DirectoryInfo directoryInfo = new DirectoryInfo(#"C:\Temp");
ProcessDirectory(directoryInfo); // Process the directory and extract any zip files.
int count = 0;
foreach (DirectoryInfo subdirectory in directoryInfo.EnumerateDirectories())
{
if (subdirectory.Name.EndsWith(".ExtractedFiles")) // Count only extracted zip files in root directory.
{
count = CountFiles(subdirectory, count);
}
}
DeleteIntermediateFiles(directoryInfo); // Delete the extracted files.
Console.WriteLine(count);
}
public static void ProcessDirectory(DirectoryInfo directoryInfo)
{
foreach (DirectoryInfo subdirectory in directoryInfo.EnumerateDirectories())
{
ProcessDirectory(subdirectory); //Process subdirectories.
}
ProcessFiles(directoryInfo); //Process files.
}
private static void ProcessFiles(DirectoryInfo directoryInfo)
{
foreach (FileInfo file in directoryInfo.EnumerateFiles())
{
if (file.Extension.Equals(".zip")) // extract zip files.
{
var extractFilesDirectory = directoryInfo.CreateSubdirectory(
Path.GetFileNameWithoutExtension(file.Name) + ".ExtractedFiles");
ZipFile.ExtractToDirectory(file.FullName, extractFilesDirectory.FullName);
ProcessDirectory(extractFilesDirectory); //process extracted files.
}
}
}
public static int CountFiles(DirectoryInfo directoryInfo, int count)
{
foreach (DirectoryInfo subdirectory in directoryInfo.EnumerateDirectories())
{
count = CountFiles(subdirectory, count);
}
foreach (var fileInfo in directoryInfo.GetFiles())
{
if (fileInfo.Extension != ".zip") //exclude zip files while counting.
count++;
}
return count;
}
public static void DeleteIntermediateFiles(DirectoryInfo directoryInfo)
{
foreach (DirectoryInfo subdirectory in directoryInfo.EnumerateDirectories())
{
if (subdirectory.Name.EndsWith(".ExtractedFiles"))
{
Directory.Delete(subdirectory.FullName, true);
}
}
}
}
}
Related
As the title says I'm trying to count the number of file in a directory and subdirectories.
I tried with a foreach loop like that :
public static int hello(string path)
{
string[] files = Directory.GetFiles(path);
string[] dirs = Directory.GetDirectories(path);
int cpt = 0;
foreach (var file in files)
{
try
{
Console.WriteLine(file);
cpt++;
}
catch { }
}
foreach (var directory in dirs)
{
try
{
hello(directory);
}
catch { }
}
return cpt;
}
And the returned value is always the number of file contained in the first path, the cpt var don't get incremented by the number of files in the others directories and subdirectories.
It's strange since the Console.WriteLine(file) shows all the files path in the console box.
It looks like a small issue but I don't really know how to solve it, I don't want to use SearchOption method but I really want to use cpt and increment it at each file.
SOLVED with the following code :
public static int hello(string path)
{
string[] files = Directory.GetFiles(path);
string[] dirs = Directory.GetDirectories(path);
int cpt = 0;
foreach (var file in files)
{
try
{
Console.WriteLine(file);
cpt++;
}
catch { }
}
foreach (var directory in dirs)
{
try
{
cpt+=hello(directory);
}
catch { }
}
return cpt;
}
Thanks to #steryd !
When you descend down the directories you're not saving the count. cpt is unique for each invocation of hello()
One Question about coding (Visual Studio C# Windows form Application) There have Two folder: (Source and Target) and I build 1 button "Copy". In (Source) folder have random folders such "20190401", "20190402", "20190403", "20180401", "20170401" and "20160401". Every these folders have [10] ".txt" files. What is the coding if I only want to copy all "201904**" folders with [3] ".txt" files inside to "Target" folder?
Here my code for now, after I click a button the folder wouldn't copy. I guess there have some problem with this codes and I still not found it until. Hope you guys can help me, thank you.
*namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string FROM_DIR = "C:/Users/Desktop/Source/";
string TO_DIR = "C:/Users/Desktop/Target/";
DirectoryInfo diCopyForm = new DirectoryInfo(FROM_DIR);
DirectoryInfo[] fiDiskfiles = diCopyForm.GetDirectories();
string directname = "201904";
string filename = ".txt";
foreach (DirectoryInfo newfile in fiDiskfiles)
{
try
{
if (newfile.Name == "2019")
{
foreach (DirectoryInfo direc in newfile.GetDirectories())
if (direc.Name.StartsWith(directname))
{
int count = 0;
foreach (FileInfo file in direc.GetFiles())
{
if (file.Name.EndsWith(filename))
{
count++;
}
}
if (count == 3)
{
DirectoryCopy(direc.FullName,Path.Combine(TO_DIR,direc.Name), true);
count = 0;
MessageBox.Show("success");
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
{
// Get the subdirectories for the specified directory.
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
if (!dir.Exists)
{
throw new DirectoryNotFoundException("Source directory does not exist or could not be found: "+ sourceDirName);
}
DirectoryInfo[] dirs = dir.GetDirectories();
// If the destination directory doesn't exist, create it.
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
// Get the files in the directory and copy them to the new location.
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
string temppath = Path.Combine(destDirName, file.Name);
file.CopyTo(temppath, false);
}
// If copying subdirectories, copy them and their contents to new location.
if (copySubDirs)
{
foreach (DirectoryInfo subdir in dirs)
{
string temppath = Path.Combine(destDirName, subdir.Name);
DirectoryCopy(subdir.FullName, temppath, copySubDirs);
}
}
}
}
*}
By clicking the button, automatically copy all "201904**" folder and 3 ".txt files in (Source) folder to (target folder).
You didn't say which 3 txt files you want to copy so the code below copies all txt files, please explain how you select the files and I'll edit the code.
const string Source = #"C:\Users\Desktop\Source\";
const string Target = #"C:\Users\Desktop\Target\";
const string StartsWith = "201904";
const string FileType = "txt";
public static void Copy()
{
if (!Directory.Exists(Source)) //Check if the source directory exists
throw new Exception("Source directory is missing!");
Directory.CreateDirectory(Target); //If the target directory doesn't exists it will create one
var Directories = Directory.GetDirectories(Source, $"{StartsWith}*"); //Get directories which match the search pattern
for (int i = 0; i < Directories.Length; i++)
{
DirectoryInfo directory = new DirectoryInfo(Directories[i]);
Directory.CreateDirectory($"{Target}{directory.Name}"); //Create the directory in the target folder
var Files = Directory.GetFiles($"{Source}{directory.Name}", $"*.{FileType}"); //Get files
for (int j = 0; j < Files.Length; j++)
{
FileInfo file = new FileInfo(Files[j]);
File.Copy($"{Source}{directory.Name}" + #"\" + file.Name, $"{Target}{directory.Name}" + #"\" + file.Name); //Copy the file to the target folder
}
}
}
This code selects all directories which start with "201904" and all txt files inside them and copies it to the target folder.
EDIT: Fixed a mistake in the code
Files and folders before the set date are deleted codes.
However, there is a problem.
I want to check the file and delete in the root folder and check the file and delete in the subfolder only once
but check the file in the root folder after delete the file in the subfolder.
I do not want to repeatedly check the file that I already confirmed.
public void FolderAndFileDelete(DirectoryInfo directoryInfo, SQLiteConnection connection, HashSet<string> splitedExtension, DateTime setTime)
{
FileInfo[] files = directoryInfo.GetFiles();
DirectoryInfo[] directoryInfos = directoryInfo.GetDirectories();
if (files != null)
{
foreach (var file in files)
{
file.Delete();
}
if (subFolderRemoveCheckBox.Checked == true)
{
foreach (DirectoryInfo subfolder in directoryInfos)
{
if (subfolder.GetFiles().Length == 0)
{
subfolder.Delete();
}
else if (subfolder.GetFiles().Length != 0)
{
this.FolderAndFileDelete(subfolder, connection, splitedExtension, setTime);
}
if (!subfolder.Exists)
return;
}
}
}
}
How can I fix it?
Your method can be reduced to something a little simpler, since you can pass true to the Delete method of a DirectoryInfo if you want it to remove all files and sub-directories. Note that I added a bool parameter to specify if sub-folders should be removed, so you would pass subFolderRemoveCheckBox.Checked for this argument:
public void DeleteContents(DirectoryInfo directoryInfo, bool includeSubFolders = false)
{
foreach (var file in directoryInfo.GetFiles())
{
file.Delete();
}
if (includeSubFolders)
{
foreach (var subDirectory in directoryInfo.GetDirectories())
{
subDirectory.Delete(true);
}
}
}
I have the following code:
public static void readtext(string pathtoText)
{
if (File.Exists(pathtoText))
{
string[] lines = System.IO.File.ReadAllLines(pathtoText);
// Display the file contents by using a foreach loop.
foreach (string line in lines)
{
clearPath(line);
}
}
else
{
Console.WriteLine("{0} doesn't exist, or isn't a valid text file", pathtoText);
}
}
public static void clearPath(string path)
{
if(Directory.Exists(path))
{
int directoryCount = Directory.GetDirectories(path).Length;
if(directoryCount > 0)
{
Console.WriteLine("{0} has Subdirectories to Remove", path);
DirectoryInfo di = new DirectoryInfo(path);
foreach (DirectoryInfo dir in di.GetDirectories())
{
dir.Delete(true);
}
}
else
{
Console.WriteLine("{0} has no directories to remove", path);
}
int fileCount = Directory.GetFiles(path).Length;
if (fileCount > 0)
{
Console.WriteLine("{0} has files to Remove", path);
System.IO.DirectoryInfo di = new DirectoryInfo(path);
foreach (FileInfo file in di.GetFiles())
{
try
{
file.Delete();
}
catch(System.IO.IOException)
{
Console.WriteLine("Please Close the following File {0}", file.Name);
}
}
}
}
else
{
Console.WriteLine("Path Doesn't Exist {0}", path);
}
}
My function reads directories from a text file and passes it to clearPath which checks if the directory exists, and if so, cleans it. My problem is that, if a directory doesn't exist, it stops the program(it doesn't move to the next directory to check if it exists and clean, the for each loop just stops) .
How do I get it to the next directory even if specific directory doesn't exist?
it is possible that you have empty lines in your file?
you can try something like that:
foreach (string line in lines)
{
if (!String.IsNullOrWhiteSpace(line))
{
clearPath(line.trim());
}
}
I found the code below on stack overflow which I tried but didn't know how to use it fully.
Basically I want to be able to zip all the files separately using foreach loop but I won't have a list of the files as they change each time.
So how can I get a list of the folders/directories inside the root directory into an array?
public static void CreateZipFile(string fileName, IEnumerable<string> files)
{
var zip = ZipFile.Open(fileName, ZipArchiveMode.Create);
foreach (var file in files)
{
zip.CreateEntryFromFile(file, Path.GetFileName(file), CompressionLevel.Optimal);
}
zip.Dispose();
}
Normally I just use DotNetZip
And this code:
using (var file = new ZipFile(zipName))
{
file.AddFiles(fileNames, directoryPathInArchive);
file.Save();
}
Where zipName is the name of zip archive you want to create and fileNames are names of files you want to put in it.
you need little script for this
public static class ZipUtil
{
public static void CreateFromMultifleFolders(string targetZip, string[] foldersSrc, string[] fileSrc = null, CompressionLevel compressionLevel = CompressionLevel.Fastest)
{
if (File.Exists(targetZip))
File.Delete(targetZip);
using (ZipArchive archive = ZipFile.Open(targetZip, ZipArchiveMode.Create))
{
foreach (string dir in foldersSrc)
AddFolederToZip(dir, archive, Path.GetFileName(dir), compressionLevel);
if(fileSrc != null)
foreach (string file in fileSrc)
archive.CreateEntryFromFile(file, Path.GetFileName(file), compressionLevel);
}
}
private static void AddFolederToZip(string folder, ZipArchive archive, string srcPath, CompressionLevel compressionLevel)
{
srcPath += "/";
foreach (string dir in Directory.GetDirectories(folder))
AddFolederToZip(dir, archive, srcPath + Path.GetFileName(dir), compressionLevel);
foreach (string file in Directory.GetFiles(folder))
archive.CreateEntryFromFile(file, srcPath + Path.GetFileName(file), compressionLevel);
}
}