System.UnauthorizedAccessException when getting files - c#

I've asked a very similar question before here. But that was about getting directories, and this is about files. And these codes are a bit different from each other. Ever since I've been trying to convert this to make it look like the answer on my old question, I haven't been able to make it work.
string[] files = Directory.GetFiles(ScanPath, "*.*", System.IO.SearchOption.AllDirectories);
DateTime From = DateTime.Now.AddHours(-24);
DateTime To = DateTime.Now;
foreach (string name in files)
{
FileInfo file = new FileInfo(name);
string fullname = file.FullName;
if (file.LastWriteTime >= From & file.LastWriteTime <= To && file.Length >= ScanSize)
Console.WriteLine(file.FullName + " ; " + "last changed at " + " ; " + file.LastWriteTime.ToString());
}
I've been getting the same errors as I explained in the other question. Because I don't know where to put the code of the foreach in a recursion. Since it's not an enumeration but a Directory.GetFiles().
The error occurs with:
Directory.GetFiles(ScanPath, "*", SearchOption.AllDirectories);
because this gets all the files of the directories at once. But if I remove it, it only gets the files in the given path, without any of the files in the subdirectories. So I was told to apply recursion.
I am the administrator of the system and I plan to run this on the entire data drive. D:\
I'm hoping anyone here knows a good example.

Your app could not have access rights to some folders, for others you can use the following code:
void DiscoverDirs(string where, List<string> files, Func<FileInfo, bool> filter)
{
try
{
var di = new DirectoryInfo(where);
files.AddRange(di.EnumerateFiles().Where(filter).Select(x => x.FullName));
foreach (var dir in Directory.GetDirectories(where))
{
DiscoverDirs(dir, files, filter);
}
}
catch
{
// no access fo this dir, ignore
}
}
Usage:
DateTime From = DateTime.Now.AddHours(-24);
DateTime To = DateTime.Now;
var ScanSize = 5*1024*1024;
var list = new List<string>();
DiscoverDirs(#"C:\", list,
file => file.LastWriteTime >= From & file.LastWriteTime <= To && file.Length >= ScanSize);
foreach (string name in list)
{
FileInfo file = new FileInfo(name);
string fullname = file.FullName;
Console.WriteLine(file.FullName + " ; " + "last changed at " + " ; " + file.LastWriteTime.ToString());
}

You might be getting "UnauthorizedAccessException" while accessing the some of the system directories.List of the directory causing the problems are directories which are actually just redirection to other directory.
May be you can tried out the following code if it helps-
try
{
foreach (String file in Directory.GetFiles(directoryName, pattern, SearchOption.TopDirectoryOnly))
{
// do stuff
}
catch (UnauthorizedAccessException uae)
{
//handle
}
catch (Exception e)
{
//handle
}
Alternative:
string[] directories = Directory.GetDirectories(ScanPath);
foreach (string directory in directories)
{
string[] filesinCurrentDirectory = Directory.GetFiles(directory, "*.*", System.IO.SearchOption.AllDirectories);
foreach (string file in filesinCurrentDirectory)
{
MessageBox.Show(file);
}
}

Related

What is the best way to copy a list of files with these variable filenames using Path.Combine

I have source directories c:\source\yyyy-MM-dd where yyyy-MM-dd represents a range of dates, and a destination directory e:\destination. I need to look for multiple filenames in each date directory in that range of dates and only copy (filenameA*.*, filenameB*.*, filenameC*.*). I then need to create the date directories from the range of dates and copy the associated files found into their respective directories.
I'm using two datetimepickers to get the range of dates. I have that foreach logic working fine. I'm only struggling with the best way to use Path.Combine to create the destination folders and copy each of the files. I think I'm doing unnecessary work in my existing code, and I keep confusing myself:
private async void ProcessFiles()
{
// create a list of topics
var topics = topicsBox.CheckedItems.Cast<string>().ToList();
// create a list of source directories based on date range
var directories = new List<string>();
var folders = new List<string>();
for (DateTime date = dateTimePicker1.Value.Date;
date.Date <= dateTimePicker2.Value.Date;
date = date.AddDays(1))
{
var dateDir = _tracePath + #"\" + date.ToString("yyyy-MM-dd") + #"\";
directories.Add(dateDir);
folders.Add(#"\" + date.ToString("yyyy-MM-dd") + #"\");
}
// create a list of source files to copy and destination
foreach (var path in directories)
{
var path1 = path;
try
{
foreach (var files2 in folders)
{
var destPath = textBox1.Text + #"\" + textBox4.Text + files2;
foreach (var files in topics)
{
if (!Directory.Exists(path1))
{
toolStripStatusLabel1.ForeColor = Color.Red;
toolStripStatusLabel1.Text = ("Could not find \"" + path1 +
"\" Check start and end date.");
}
else
{
foreach (
string sourcePath in
Directory.EnumerateFiles(path1, files + "*.*", SearchOption.AllDirectories))
{
var filename = Path.GetFileName(sourcePath); // get each filename in source directory
var fullDestPath = Path.Combine(destPath, filename); // create the destination folder name
Directory.CreateDirectory(sourcePath.Replace(sourcePath, destPath)); // create the destination folder
// copy the files to the temp folder asynchronously
using (FileStream SourceStream = File.Open(sourcePath, FileMode.Open))
{
using (FileStream DestinationStream = File.Create(fullDestPath))
{
xferBtn.Enabled = false;
toolStripStatusLabel1.ForeColor = Color.Green;
toolStripStatusLabel1.Text = "Copying " + sourcePath;
await SourceStream.CopyToAsync(DestinationStream);
toolStripStatusLabel1.Text = "Copying complete!";
}
}
}
}
}
}
}
catch (Exception e)
{
}
}
}
To start, it may be easier to break things apart into separate methods to keep track of tasks. I find this to be easier when doing multiple tasks in one method. I just created a simple test to copy files from a source to destination. This won't match your logic, but it may lead you in the right direction. When you enumerate over files, you get an IEnumerable object to work with. You can use that to just iterate over your file paths. Also, you have a DirectoryInfo object you can use to check for directory creation before copying. I also did not follow your logic with source/destination stream, but instead just used the System.File.IO.Copy method that show how Path.Combine works. This is an easy way to combine say a path to a directory and a file without concatenation. Its basically a string.Format("{0}", somthingToAppend).
private void BtnProcess_Click(object sender, EventArgs e)
{
// create a list of source directories based on date range
List<string> sourceDirectories = new List<string>();
List<string> destDirectories = new List<string>();
sourceDirectories.Add("C:\\Users\\Eric\\Desktop\\Dir1");
sourceDirectories.Add("C:\\Users\\Eric\\Desktop\\Dir2");
destDirectories.Add("C:\\Users\\Eric\\Desktop\\Dest1");
destDirectories.Add("C:\\Users\\Eric\\Desktop\\Dest2");
// create a list of source files to copy and destination
foreach (var path in sourceDirectories)
{
if (!Directory.Exists(path))
{
//Error message here if path does not exist or continue with the next path
continue;
}
try
{
IEnumerable<string> paths = Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories);
DirectoryInfo destPathInfo = Directory.CreateDirectory(destDirectories[0]); // create the destination folder
if (destPathInfo.Exists)
{
foreach (var p in paths)
{
string destination = System.IO.Path.Combine(destDirectories[0], System.IO.Path.GetFileName(p));
System.IO.File.Copy(p, destination);
}
destDirectories.RemoveAt(0);
}
}
catch (Exception ex)
{
}
}
}

This code taken from microsoft is only copying the text files in the main directory not sub-directories

Taken from: http://msdn.microsoft.com/en-us/library/dd383571.aspx
I've modified it to copy files, but even when I had it exactly as microsofts example, it still is ignoring the text file I placed in a subdirectory as a test...I'm dying to know what is going on here since I thought "SearchOption.AllDirectories" took care of that...
{
string sourceDirectory = #"C:\Users\root\Desktop\bms 2013\bms 2013";
string archiveDirectory = #"C:\Users\root\Desktop\test";
try
{
var txtFiles = Directory.EnumerateFiles(sourceDirectory, "*.txt", SearchOption.AllDirectories);
foreach (string currentFile in txtFiles)
{
string fileName = currentFile.Substring(sourceDirectory.Length + 1);
File.Copy(currentFile, Path.Combine(archiveDirectory, fileName));
}
}
catch (Exception)
{
// Console.WriteLine(e.Message);
}
}

Making an iso file from a directory using DiscUtils

Iam trying to build an iso file from a directory with discutils. This code works fine with a couple of files but after a while i throws an exception stating that "An object with the same key already exists" at "isoBuilder.AddFile(fileOnIso,br.BaseStream);". I don't understand why this happens can someone please shed some light?
public void AddtoISO(string directory,string isoFile)
{
BinaryReader br;
long bytesRemain = 0;
long totalBytesWritten = 0;
DirectoryInfo rootDirToAdd = new DirectoryInfo(sourceName);
DirectoryInfo currentDirToAdd = new DirectoryInfo(directory);
try
{
foreach (FileInfo file in currentDirToAdd.GetFiles())
{
string fileFullPath = file.FullName;
string fileOnIso = fileFullPath.Substring(fileFullPath.IndexOf(rootDirToAdd.Name) + rootDirToAdd.Name.Length + 1);
Console.WriteLine(fileOnIso);
br = new BinaryReader(file.OpenRead());
while(totalBytesWritten < file.Length)
{
bytesRemain = file.Length - totalBytesWritten;
br.ReadBytes(blockSize);
isoBuilder.AddFile(fileOnIso,br.BaseStream);
if(bytesRemain<blockSize)
{
totalBytesWritten += bytesRemain;
totalBytesAdded += bytesRemain;
}
else
{
totalBytesWritten += blockSize;
totalBytesAdded += blockSize;
}
}
itemsAdded++;
totalBytesWritten = 0;
}
foreach (DirectoryInfo subdir in currentDirToAdd.GetDirectories())
{
string folderFullPath = subdir.FullName;
string folderOnIso = folderFullPath.Substring(folderFullPath.IndexOf(rootDirToAdd.Name) + rootDirToAdd.Name.Length + 1);
isoBuilder.AddDirectory(folderOnIso);
itemsAdded++;
AddtoISO(subdir.FullName,isoFile,ctoken);
}
isoBuilder.Build(isoFile);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
}
Update
An other possible implementation avoiding streams, the drawback is that it takes too much time (over 30 mins) on a 3GB iso which when built with ultraiso for example, it takes aprox 4 mins.. any ideas?
public void AddtoISO(string directory,string isoFile)
{
try
{
DirectoryInfo rootDirToAdd = new DirectoryInfo(sourceName);
DirectoryInfo currentDirToAdd = new DirectoryInfo(directory);
foreach (FileInfo file in currentDirToAdd.GetFiles())
{
string fileOnHdd = file.FullName;
string fileOnIso = fileOnHdd.Substring(fileOnHdd.IndexOf(rootDirToAdd.Name) + rootDirToAdd.Name.Length + 1);
Console.WriteLine(fileOnIso);
isoBuilder.AddFile(fileOnIso,fileOnHdd);
itemsAdded++;
}
foreach (DirectoryInfo subdir in currentDirToAdd.GetDirectories())
{
itemsAdded++;
AddtoISO(subdir.FullName,isoFile,ctoken);
}
isoBuilder.Build(isoFile);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
}
Update:
The exception is thrown when ever the directory structure is the following:
\boot\boot
It seems like it creates the key for boot directory and when it encounters boot.ext file it falsely thinks that it is a double addition. In other words when the files contains the name of its containing directory.
Test building dsl-4.11.rc1.iso
index.html
boot
boot\isolinux
boot\isolinux\boot.cat
boot\isolinux\boot.msg
boot\isolinux\f2
boot\isolinux\f3
boot\isolinux\german.kbd
boot\isolinux\isolinux.bin
boot\isolinux\isolinux.cfg
boot\isolinux\linux24
boot\isolinux\logo.16
boot\isolinux\minirt24.gz
KNOPPIX
KNOPPIX\KNOPPIX
Problem on KNOPPIX\KNOPPIX
Update 2
At last some progress.. the error is not in any of the given paths but im my assumption that i had to keep calling isobuilder.Addfile() until the filestream has been added to the iso entirely.
I just had to move:
isoBuilder.AddFile(fileOnIso,br.BaseStream);
Before the foreach closing bracket. This way it will no have to be added again and again in the iso.
One final problem is at the line
isoBuilder.Build(isoFile);
Where it complains about the file being closed. I tried to correct it with:
FileInfo fi = new FileInfo(isoFile);
isoBuilder.Build(fi.OpenWrite());
But it didnt help. Please someone give me the final push to solve it.
I know this is very OLD but I thought Id post if anyone else needed help with this in future.
Below is a fast and efficient function I use to build an ISO using DiscUtils.Iso9660
public string CreateIsoImage(string sourceDrive, string targetIso, string volumeName)
{
try
{
var srcFiles = Directory.GetFiles(sourceDrive, "*", SearchOption.AllDirectories);
var iso = new CDBuilder
{
UseJoliet = true,
VolumeIdentifier = volumeName
};
foreach (var file in srcFiles)
{
var fi = new FileInfo(file);
if (fi.Directory.Name == sourceDrive)
{
iso.AddFile($"{fi.Name}", fi.FullName);
continue;
}
var srcDir = fi.Directory.FullName.Replace(sourceDrive, "").TrimEnd('\\');
iso.AddDirectory(srcDir);
iso.AddFile($"{srcDir}\\{fi.Name}", fi.FullName);
}
iso.Build(targetIso);
return "Success";
}
catch (Exception ex)
{
return ex.Message;
}
}
Usage:
var res = CreateIsoImage("D:\\", "C:\\Temp\\MyIsoImage.iso", "MyVolumeName");
MessageBox.Show(res);

Recursively append directory names to a string

i got a big problem , alright so here is the problem :
I am trying to get the fileinfo from a directory so that i can list it on listview .
When i recursively search for files using that method :
private void Get_Files(string path)
{
DirectoryInfo di = new DirectoryInfo(path);
FileInfo[] fi = di.GetFiles();
foreach (FileInfo Info in fi)
{
try
{
Files.Add(Info.FullName);
}
catch(Exception ee)
{
MessageBox.Show(ee.Message);
}
}
foreach (DirectoryInfo DInfo in di.GetDirectories())
{
Get_Files(DInfo.FullName);
}
}
Sometimes the path is longer than 260 Characters , so i am getting that error :
Path is too long and it should not exceed 260 Characters , i have searched over the internet and people said that it has no solution , but i have figured out a solution my self .
Solution : is creating a string and appending each path of the path to that string , so i never get that error when saving the whole path into string.
Think of it as taking the path apart and taking each piece and appending it to the string.
So here is the solution i figured :
List<string> Files = new List<string>();
string completepath = string.Empty;
string current_dire_name = string.Empty;
private void Get_Files(string path)
{
DirectoryInfo di = new DirectoryInfo(path);
FileInfo[] fi = di.GetFiles();
foreach (FileInfo Info in fi)
{
try
{
completepath += "\\" + Info.Name;
Files.Add(completepath);
string remove_file_name = completepath;
remove_file_name = remove_file_name.Replace("\\" + Info.Name, "");
completepath = remove_file_name;
}
catch(Exception ee)
{
if(DialogResult.Yes == MessageBox.Show("Error at the Get_Files Method and Error message :\n\n" + ee.Message + "\n\nQuit Application now ?","",MessageBoxButtons.YesNo,MessageBoxIcon.Question))
{
Environment.Exit(0);
}
}
}
foreach (DirectoryInfo DInfo in di.GetDirectories())
{
string remove_folder_name = completepath;
remove_folder_name = remove_folder_name.Replace("\\" + current_dire_name, "");
completepath = remove_folder_name;
current_dire_name = DInfo.Name;
completepath += "\\" + DInfo.Name;
Get_Files(DInfo.FullName);
}
}
Okay , that method saved me , but it generated wrong path , i mean something is not correct , lets say if path should be : C:\Folder1\Folder2\Folder3\file.txt
The generated path is : C:\Folder1\file.txt , something like that ....
I know that the method i did has something wrong especially the recursive appending.
I hope someone figure it with me , so that people can avoid the long path exception.
You're looking for the .Net Long Path library, which uses the \\?\ prefix with the Windows APIs to avoid the restriction entirely.

C#:Getting all image files in folder

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

Categories