I want to find all files in whole harddrive (.jpg, .png, .apk and a few other formats) but this code is not working..all it does is : for example if in my 'D:\' drive I have: 1)a image file 'i1', 2)a folder 'f1' which has image file and 3) another folder 'f2' which has image file and 'f2' contains folder 'f3' which has image file .It only performs 'calcFile()' on contents inside f1 and f2 but not on contents of f3 and i1 same happens with all other partitions .What is wrong here? Any help is appreciated.
I hope you understand what is happening because that's the easiest way I could explain my situation, if more info is required just tell me. thanks :)
public void calcDirectory(string token)
{
var validExtensions = new[]
{
".jpg", ".png", ".apk"
};
foreach (string s in Directory.GetLogicalDrives())
{
DriveInfo driveInfo = new DriveInfo(s);
if (driveInfo.IsReady)
{
foreach (string d in Directory.GetDirectories(s))
{
FileAttributes attrs1 = File.GetAttributes(d);
if (!attrs1.HasFlag(FileAttributes.ReparsePoint))
{
if (!attrs1.HasFlag(FileAttributes.System))
{
string[] allFilesInDir = Directory.GetFiles(d);
for (int i = 0; i < allFilesInDir.Length; i++)
{
string file = allFilesInDir[i];
string extension = Path.GetExtension(file);
if (validExtensions.Contains(extension))
{
string p = Path.GetFullPath(file);
FileAttributes attrs = File.GetAttributes(p);
if (attrs.HasFlag(FileAttributes.ReadOnly))
{
File.SetAttributes(p, attrs & ~FileAttributes.ReadOnly);
calcFile(file, token);
}
else
{
calcFile(file, token);
}
}
}
}
}
}
}
}
}
and I call the calcDirectory() here
public void start()
{
string token = File.ReadAllText(tokencalcalculated);
calcDirectory(token);
}
I created a function based on your code that will recursively search the directory for anything matching your pattern. You'll have to call this from your loop of the base directories.
public static void crawlDirectory(string token,string directory)
{
if (string.IsNullOrEmpty(directory)) return;
var validExtensions = new[]
{
".jpg", ".png", ".apk"
};
foreach (string d in Directory.GetDirectories(directory))
{
FileAttributes attrs1 = File.GetAttributes(d);
if (!attrs1.HasFlag(FileAttributes.ReparsePoint) && !attrs1.HasFlag(FileAttributes.System))
{
string[] allFilesInDir = Directory.GetFiles(d);
for (int i = 0; i < allFilesInDir.Length; i++)
{
string file = allFilesInDir[i];
string extension = Path.GetExtension(file);
if (validExtensions.Contains(extension))
{
string p = Path.GetFullPath(file);
FileAttributes attrs = File.GetAttributes(p);
if (attrs.HasFlag(FileAttributes.ReadOnly))
{
File.SetAttributes(p, attrs & ~FileAttributes.ReadOnly);
calcFile(file, token);
}
else
{
calcFile(file, token);
}
}
}
}
crawlDirectory(d, token);
}
}
You are only enumerating the root directories but no subdirectories. Instead of Directory.GetDirectories(s) use
foreach(string d in Directory.GetDirectories(s, "*", SearchOption.AllDirectories))
But be aware of infinite loops due to links in your subdirectories (see MSDN on SearchOption.AllDirectories).
And you should be aware of user access rights. You should put a try...catch around your GetFiles part in case you don't have access rights for a specific directory (See this question).
Related
:)
So I have a hw (I have to run project from console): I have to count the number of sub directories in specific directory (the user writes in this way " [path] [extension] [-r] ")
So if user writes the directory and doesn't write the extension, my program just counts the number of sub directories.
BUT if user writes the parameter, for example, .exe, .txt, .cs, I have to count the number of files with this specific extension in the specific directory and return this number.
Sooo, everything is good with the first part - my program works correctly and count the number of sub directories, recursively (if I write the parameter -r) or not (if I don't). The problem is with counting files with extension.
Here is my function for counting sub directories:
class Data
{
public string curDir = Directory.GetCurrentDirectory();
public string Extension = "";
public bool isRecursive;
}
public static int CountDir(Data data)
{
string[] dirs = Directory.GetDirectories(data.curDir);
int res = dirs.Length;
int resFiles = files.Length;
try
{
if (data.isRecursive)
{
foreach (string subdir in dirs)
{
Data d = new Data();
d.curDir = subdir;
d.Extension = data.Extension;
d.isRecursive = data.isRecursive;
res += CountDir(d);
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex.Message}");
}
return res;
}
So I tried to do the similar thing in this method, but for files and I'm a bit confused:
string[] files = Directory.GetFiles(data.curDir);
int resFiles = files.Length;
foreach (string ext in files)
{
FileInfo fi = new FileInfo(ext);
if (data.Extension != "")
{
if (fi.Extension == data.Extension)
{
//res = 0;
//++res;
//what am I supposed to do here?..
}
}
}
I also wonder if I can do this in the same method (CountDir).
Thank you so much in advance!
Edit: I know about SearchOptions.AllDirectories method, but I don't know in advance which extension user will write
I would put the file count logic in its own method since the goal is to get the number of files for a specific directory rather than all sub-directories. Here's an example based on your sample code:
public static int countFiles(Data data)
{
string[] files = new string[0];
try
{
files = Directory.GetFiles(data.curDir, $"*{data.Extension}");
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex.Message}");
}
return files.Length;
}
I am using the following code to extract all files in a folder
using (ZipArchive archive = new ZipArchive(zipStream))
{
archive.ExtractToDirectory(location);
}
But if one file exist then it throws an exception. Is there is any way to tell the Compression API to replace the existing files.
I found one way is to get all the file names first then check whether file exist and delete it. But this is somehow very costly for me.
I have created an extension. any comment to it improve will be appreciated,
public static class ZipArchiveExtensions
{
public static void ExtractToDirectory(this ZipArchive archive, string destinationDirectoryName, bool overwrite)
{
if (!overwrite)
{
archive.ExtractToDirectory(destinationDirectoryName);
return;
}
DirectoryInfo di = Directory.CreateDirectory(destinationDirectoryName);
string destinationDirectoryFullPath = di.FullName;
foreach (ZipArchiveEntry file in archive.Entries)
{
string completeFileName = Path.GetFullPath(Path.Combine(destinationDirectoryFullPath, file.FullName));
if (!completeFileName.StartsWith(destinationDirectoryFullPath, StringComparison.OrdinalIgnoreCase))
{
throw new IOException("Trying to extract file outside of destination directory. See this link for more info: https://snyk.io/research/zip-slip-vulnerability");
}
if (file.Name == "")
{// Assuming Empty for Directory
Directory.CreateDirectory(Path.GetDirectoryName(completeFileName));
continue;
}
file.ExtractToFile(completeFileName, true);
}
}
}
This code will not throw exception when the folder is not exist, instead of that it will create the folder.
public static class ZipArchiveExtensions
{
public static void ExtractToDirectory(this ZipArchive archive, string destinationDirectoryName, bool overwrite)
{
if (!overwrite)
{
archive.ExtractToDirectory(destinationDirectoryName);
return;
}
foreach (ZipArchiveEntry file in archive.Entries)
{
string completeFileName = Path.Combine(destinationDirectoryName, file.FullName);
string directory = Path.GetDirectoryName(completeFileName);
if (!Directory.Exists(directory))
Directory.CreateDirectory(directory);
if (file.Name != "")
file.ExtractToFile(completeFileName, true);
}
}
}
Take a look at this: Creating zip files easily in .NET 4.5. Your problem seems to be adressed. Alternatively, you can also check DotNetZip.
As I'm a total Linq fan, the Linq-ish way just for reference:
using (var strm = File.OpenRead(zipPath))
using (ZipArchive a = new ZipArchive(strm))
{
a.Entries.Where(o => o.Name == string.Empty && !Directory.Exists(Path.Combine(basePath, o.FullName))).ToList().ForEach(o => Directory.CreateDirectory(Path.Combine(basePath, o.FullName)));
a.Entries.Where(o => o.Name != string.Empty).ToList().ForEach(e => e.ExtractToFile(Path.Combine(basePath, e.FullName), true));
}
You can extract files to some temp directory and than copy files with the
"File.Copy" with the ovveride option true to your destination directory
I know that it's not a perfect solution , but this way you do not need to
check if file exist
Here is a method that takes a path to the zip file.
Based on the accepted answer.
public void ExtractZipFileToDirectory(string sourceZipFilePath, string destinationDirectoryName, bool overwrite)
{
using (var archive = ZipFile.Open(sourceZipFilePath, ZipArchiveMode.Read))
{
if (!overwrite)
{
archive.ExtractToDirectory(destinationDirectoryName);
return;
}
DirectoryInfo di = Directory.CreateDirectory(destinationDirectoryName);
string destinationDirectoryFullPath = di.FullName;
foreach (ZipArchiveEntry file in archive.Entries)
{
string completeFileName = Path.GetFullPath(Path.Combine(destinationDirectoryFullPath, file.FullName));
if (!completeFileName.StartsWith(destinationDirectoryFullPath, StringComparison.OrdinalIgnoreCase))
{
throw new IOException("Trying to extract file outside of destination directory. See this link for more info: https://snyk.io/research/zip-slip-vulnerability");
}
if (file.Name == "")
{// Assuming Empty for Directory
Directory.CreateDirectory(Path.GetDirectoryName(completeFileName));
continue;
}
file.ExtractToFile(completeFileName, true);
}
}
}
Since .NET Standard 2.1, it's as easy as setting overwriteFiles to true in:
ZipFile.ExtractToDirectory(string sourceFile, string destDir, Encoding entryNameEncoding, bool overwriteFiles)
Example:
ZipFile.ExtractToDirectory("c:\\file.zip","c:\\destination_folder", Encoding.UTF8, true);
Hi I'm using DotNetZip download from nugget.
I just simply use this code.
This will auto replace the files in the directory if exists.
"OverwriteSilently" !
using (ZipFile archive = new ZipFile(#"" + System.Environment.CurrentDirectory + "\\thezipfile.zip"))
{
archive.ExtractAll(#"" + System.Environment.CurrentDirectory, ExtractExistingFileAction.OverwriteSilently);
}
This is useful when you have zip file path
public static class ZipArchiveHelper
{
public static void ExtractToDirectory(string archiveFileName, string destinationDirectoryName, bool overwrite)
{
if (!overwrite)
{
ZipFile.ExtractToDirectory(archiveFileName, destinationDirectoryName);
}
else
{
using (var archive = ZipFile.OpenRead(archiveFileName))
{
foreach (var file in archive.Entries)
{
var completeFileName = Path.Combine(destinationDirectoryName, file.FullName);
var directory = Path.GetDirectoryName(completeFileName);
if (!Directory.Exists(directory) && !string.IsNullOrEmpty(directory))
Directory.CreateDirectory(directory);
if (file.Name != "")
file.ExtractToFile(completeFileName, true);
}
}
}
}
}
A little remade method from the answer to create all the folders
public static void ExtractToDirectory(this ZipArchive archive, string destinationDirectoryName, bool overwrite)
{
if (!overwrite)
{
archive.ExtractToDirectory(destinationDirectoryName);
return;
}
foreach (ZipArchiveEntry file in archive.Entries)
{
string completeFileName = Path.Combine(destinationDirectoryName, file.FullName);
if (file.Name == "")
{// Assuming Empty for Directory
Directory.CreateDirectory(Path.GetDirectoryName(completeFileName));
continue;
}
// create dirs
var dirToCreate = destinationDirectoryName;
for (var i = 0; i < file.FullName.Split('/').Length - 1; i++)
{
var s = file.FullName.Split('/')[i];
dirToCreate = Path.Combine(dirToCreate, s);
if (!Directory.Exists(dirToCreate))
Directory.CreateDirectory(dirToCreate);
}
file.ExtractToFile(completeFileName, true);
}
}
Looks like the only way to dodge including that blob of code is to simply delete the files before extracting the archive with del:
del (location + "\*")
using (ZipArchive archive = new ZipArchive(zipStream))
{
archive.ExtractToDirectory(location);
}
It's not exactly what the OP wanted, but it is compact.
I have an app that reads a CSV file called “words.csv”. My new requirement is that 1) it needs to ensure that there is only one CSV file in the directory before reading. 2) It should read any file with ".CSV" extension not just “words.csv” (after condition 1 is satisfied). Hope this makes sense?
Can anyone assist?
public class VM
{
public VM()
{
Words = LoadWords(fileList[0]);
}
public IEnumerable<string> Words { get; private set; }
string[] fileList = Directory.GetFiles(#"Z:\My Documents\", "*.csv");
private static IEnumerable<string> LoadWords(String fileList)
{
List<String> words = new List<String>();
if (fileList.Length == 1)
{
try
{
foreach (String line in File.ReadAllLines(fileList))
{
string[] rows = line.Split(',');
words.AddRange(rows);
}
}
catch (Exception e)
{
System.Windows.MessageBox.Show(e.Message);
}
return words;
}
}
}
You can use this code to get a list of all the csv files in a folder:
string[] fileList = Directory.GetFiles( #"Z:\My Documents\", "*.csv");
So to satisfy your conditions, this should do the trick:
string[] fileList = Directory.GetFiles( #"Z:\My Documents\", "*.csv");
if( fileList.Length == 1 )
{
//perform your logic here
}
DirectoryInfo di = new DirectoryInfo(#"Z:\My Documents");
// Get a reference to each file in that directory.
FileInfo[] fiArr = di.GetFiles();
if(fiArr.Length ==1)
{
FileInfo fri = fiArr[0];
//use fri.Extension to check for csv
//process as required
}
MSDN:DirectoryInfo.GetFiles
MSDN: FileInfo
FileInfo file = new DirectoryInfo(#"Z:\My Documents")
.EnumerateFiles("*.csv")
.SingleOrDefault();
if (file != null)
{
//do your logic
}
Linq's SingleOrDefault operator will make sure there's exactly onle file with the given pattern otherwise it will return null
I am trying to get all images from folder but ,this folder also include sub folders. like /photos/person1/ and /photos/person2/ .I can get photos in folder like
path= System.IO.Directory.GetCurrentDirectory() + "/photo/" + groupNO + "/";
public List<String> GetImagesPath(String folderName)
{
DirectoryInfo Folder;
FileInfo[] Images;
Folder = new DirectoryInfo(folderName);
Images = Folder.GetFiles();
List<String> imagesList = new List<String>();
for (int i = 0; i < Images.Length; i++)
{
imagesList.Add(String.Format(#"{0}/{1}", folderName, Images[i].Name));
// Console.WriteLine(String.Format(#"{0}/{1}", folderName, Images[i].Name));
}
return imagesList;
}
But how can I get all photos in all sub folders? I mean I want to get all photos in /photo/ directory at once.
Have a look at the DirectoryInfo.GetFiles overload that takes a SearchOption argument and pass SearchOption.AllDirectories to get the files including all sub-directories.
Another option is to use Directory.GetFiles which has an overload that takes a SearchOption argument as well:
return Directory.GetFiles(folderName, "*.*", SearchOption.AllDirectories)
.ToList();
I'm using GetFiles wrapped in method like below:
public static String[] GetFilesFrom(String searchFolder, String[] filters, bool isRecursive)
{
List<String> filesFound = new List<String>();
var searchOption = isRecursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
foreach (var filter in filters)
{
filesFound.AddRange(Directory.GetFiles(searchFolder, String.Format("*.{0}", filter), searchOption));
}
return filesFound.ToArray();
}
It's easy to use:
String searchFolder = #"C:\MyFolderWithImages";
var filters = new String[] { "jpg", "jpeg", "png", "gif", "tiff", "bmp", "svg" };
var files = GetFilesFrom(searchFolder, filters, false);
There's a good one-liner solution for this on a similar thread:
get all files recursively then filter file extensions with LINQ
Or if LINQ cannot be used, then use a RegEx to filter file extensions:
var files = Directory.GetFiles("C:\\path", "*.*", SearchOption.AllDirectories);
List<string> imageFiles = new List<string>();
foreach (string filename in files)
{
if (Regex.IsMatch(filename, #"\.jpg$|\.png$|\.gif$"))
imageFiles.Add(filename);
}
I found the solution this Might work
foreach (string img in Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.Desktop),"*.bmp" + "*.jpg" + "SO ON"))
You need the recursive form of GetFiles:
DirectoryInfo.GetFiles(pattern, searchOption);
(specify AllDirectories as the SearchOption)
Here's a link for more information:
MSDN: DirectoryInfo.GetFiles
This allows you to use use the same syntax and functionality as Directory.GetFiles(path, pattern, options); except with an array of patterns instead of just one.
So you can also use it to do tasks like find all files that contain the word "taxes" that you may have used to keep records over the past year (xlsx, xls, odf, csv, tsv, doc, docx, pdf, txt...).
public static class CustomDirectoryTools {
public static string[] GetFiles(string path, string[] patterns = null, SearchOption options = SearchOption.TopDirectoryOnly) {
if(patterns == null || patterns.Length == 0)
return Directory.GetFiles(path, "*", options);
if(patterns.Length == 1)
return Directory.GetFiles(path, patterns[0], options);
return patterns.SelectMany(pattern => Directory.GetFiles(path, pattern, options)).Distinct().ToArray();
}
}
In order to get all image files on your c drive you would implement it like this.
string path = #"C:\";
string[] patterns = new[] {"*.jpg", "*.jpeg", "*.jpe", "*.jif", "*.jfif", "*.jfi", "*.webp", "*.gif", "*.png", "*.apng", "*.bmp", "*.dib", "*.tiff", "*.tif", "*.svg", "*.svgz", "*.ico", "*.xbm"};
string[] images = CustomDirectoryTools.GetFiles(path, patterns, SearchOption.AllDirectories);
You can use GetFiles
GetFiles("*.jpg", SearchOption.AllDirectories)
GetFiles("*.jpg", SearchOption.AllDirectories) has a problem at windows7. If you set the directory to c:\users\user\documents\, then it has an exception: because of windows xp, win7 has links like Music and Pictures in the Documents folder, but theese folders don't really exists, so it creates an exception. Better to use a recursive way with try..catch.
This will get list of all images from folder and sub folders and it also take care for long file name exception in windows.
// To handle long folder names Pri external library is used.
// Source https://github.com/peteraritchie/LongPath
using Directory = Pri.LongPath.Directory;
using DirectoryInfo = Pri.LongPath.DirectoryInfo;
using File = Pri.LongPath.File;
using FileInfo = Pri.LongPath.FileInfo;
using Path = Pri.LongPath.Path;
// Directory and sub directory search function
public void DirectoryTree(DirectoryInfo dr, string searchname)
{
FileInfo[] files = null;
var allFiles = new List<FileInfo>();
try
{
files = dr.GetFiles(searchname);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
if (files != null)
{
try
{
foreach (FileInfo fi in files)
{
allFiles.Add(fi);
string fileName = fi.DirectoryName + "\\" + fi.Name;
string orgFile = fileName;
}
var subDirs = dr.GetDirectories();
foreach (DirectoryInfo di in subDirs)
{
DirectoryTree(di, searchname);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
public List<String> GetImagesPath(String folderName)
{
var dr = new DirectoryInfo(folderName);
string ImagesExtensions = "jpg,jpeg,jpe,jfif,png,gif,bmp,dib,tif,tiff";
string[] imageValues = ImagesExtensions.Split(',');
List<String> imagesList = new List<String>();
foreach (var type in imageValues)
{
if (!string.IsNullOrEmpty(type.Trim()))
{
DirectoryTree(dr, "*." + type.Trim());
// output to list
imagesList.Add = DirectoryTree(dr, "*." + type.Trim());
}
}
return imagesList;
}
var files = new DirectoryInfo(path).GetFiles("File")
.OrderByDescending(f => f.LastWriteTime).First();
This could gives you the perfect result of searching file with its latest mod
I've got main folder:
c:\test
And there I have 2 folders: Movies and Photos.
Photos has three folders with files with the same structure: People, Animals and Buildings. I'm trying this code:
Directory.Move(#"c:\test\Movies", #"c:\test\Test");
I get exception:
File already exists
This method will move content of a folder recursively and overwrite existing files.
You should add some exception handling.
Edit:
This method is implemented with a while loop and a stack instead of recursion.
public static void MoveDirectory(string source, string target)
{
var stack = new Stack<Folders>();
stack.Push(new Folders(source, target));
while (stack.Count > 0)
{
var folders = stack.Pop();
Directory.CreateDirectory(folders.Target);
foreach (var file in Directory.GetFiles(folders.Source, "*.*"))
{
string targetFile = Path.Combine(folders.Target, Path.GetFileName(file));
if (File.Exists(targetFile)) File.Delete(targetFile);
File.Move(file, targetFile);
}
foreach (var folder in Directory.GetDirectories(folders.Source))
{
stack.Push(new Folders(folder, Path.Combine(folders.Target, Path.GetFileName(folder))));
}
}
Directory.Delete(source, true);
}
public class Folders
{
public string Source { get; private set; }
public string Target { get; private set; }
public Folders(string source, string target)
{
Source = source;
Target = target;
}
}
Update:
This is a simpler version with the use of Directory.EnumerateFiles recursively instead of using a stack.
This will only work with .net 4 or later, to us it with an earlier version of .net change Directory.EnumerateFiles to Directory.GetFiles.
public static void MoveDirectory(string source, string target)
{
var sourcePath = source.TrimEnd('\\', ' ');
var targetPath = target.TrimEnd('\\', ' ');
var files = Directory.EnumerateFiles(sourcePath, "*", SearchOption.AllDirectories)
.GroupBy(s=> Path.GetDirectoryName(s));
foreach (var folder in files)
{
var targetFolder = folder.Key.Replace(sourcePath, targetPath);
Directory.CreateDirectory(targetFolder);
foreach (var file in folder)
{
var targetFile = Path.Combine(targetFolder, Path.GetFileName(file));
if (File.Exists(targetFile)) File.Delete(targetFile);
File.Move(file, targetFile);
}
}
Directory.Delete(source, true);
}
The destination directory should not already exist - the Directory.Move method creates the destination directory for you.
ProcessStartInfo p = new ProcessStartInfo("cmd", "/c move \"c:\\test\\Movies\" \"c:\\test\Test\\"");
p.WindowStyle = ProcessWindowStyle.Hidden; //hide mode
Process.Start(p);
Is it safe for you to delete the destination folder before copying new contents to it?
Directory.Delete(#"c:\test\test");
Directory.Move(#"c:\test\movies",#"c:\test\test");
The most common 2 reasons why Directory.Move could fail are, if:
It's a different volume (you need to Copy/Delete)
It already exists (doesn't support overwrite by default)
Here is my simple solution for the second problem (overwrite):
public bool MoveDirectory(string sourceDirName, string destDirName, bool overwrite)
{
if (overwrite && Directory.Exists(destDirName))
{
var needRestore = false;
var tmpDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
try
{
Directory.Move(destDirName, tmpDir);
needRestore = true; // only if fails
Directory.Move(sourceDirName, destDirName);
return true;
}
catch (Exception)
{
if (needRestore)
{
Directory.Move(tmpDir, destDirName);
}
}
finally
{
Directory.Delete(tmpDir, true);
}
}
else
{
Directory.Move(sourceDirName, destDirName); // Can throw an Exception
return true;
}
return false;
}
You can use move method directly.
Directory.Move(#"c:\test\Movies\", #"c:\test\Test\");
The folder will be deleted and copied it into Test Folder.