I have a code like this.
IEnumerable<string> imagesFileNames = FindImages(imagesFolder);
foreach(string imageFileName in imagesFileNames)
{
//my code
//IEnumerable<string> imagesFilesNames = FindImages(imagesFolder);
// it doesn't work!!
}
Can i update the IENumerable collection in foreach loop?
Welcome to Stackoverflow. You cannot change the IEnumerable your iterating over in that loop.
It looks like you want to recursively look for files:
IEnumerable<string> imagesFileNames = FindImages(imagesFolder, "*.jpg", true);
private IEnumerable<string> FindImages(string dir, string extension, bool isRecursive)
try
{
foreach (string d in Directory.GetDirectories(dir))
{
try
{
foreach (string f in Directory.GetFiles(d, extension))
{
imagesFileNames.Add(f);
}
if (isRecursive) FindImages(d,extension, true);
}
catch (Exception)
{
}
}
}
Thank you all. I realized that after your comments , that's a bad idea.
And decided to change my method. I solved it with a timer with calling the
images' names in order.
private void timer2_Tick(object sender, EventArgs e)
{
a++;
imageFileName = "IMAGES\DB\"+a+".jpg"
\\\my code
}
Related
My code has a function that scans a root directory and showing txt files (for example) in a TreeView:
private TreeNode DirectoryToTreeView(TreeNode parentNode, string path,
string extension = ".txt")
{
var result = new TreeNode(parentNode == null ? path : Path.GetFileName(path));
foreach (var dir in Directory.GetDirectories(path))
{
TreeNode node = DirectoryToTreeView(result, dir);
if (node.Nodes.Count > 0)
{
result.Nodes.Add(node);
}
}
foreach (var file in Directory.GetFiles(path))
{
if (Path.GetExtension(file).ToLower() == extension.ToLower())
{
result.Nodes.Add(Path.GetFileName(file));
}
}
return result;
}
This function should by called from the button like:
treeView1.Nodes.Add(DirectoryToTreeView(null, #"C:\Users\Tomer\Desktop\a"));
Its obviously freezing the UI.
I am new to this and I have searched the web and nothing seemed relevant to my problem because no one used recursive function and I cant simply call BeginInvoke on the entire function because it will have no effect.
What path should I take? Maybe change the function to work with a while loop and then calling BeginInvoke inside the if statements? Creating a TreeNode object in memory to populate (which may be too large)?
You could convert the DirectoryToTreeNode method to an asynchronous method, and offload any blocking I/O operation to the ThreadPool, by using the Task.Run method:
private async Task<TreeNode> DirectoryToTreeNodeAsync(string path,
TreeNode parentNode = null)
{
var node = new TreeNode(parentNode == null ? path : Path.GetFileName(path));
string[] subdirectories = await Task.Run(() => Directory.GetDirectories(path));
foreach (string dirPath in subdirectories)
{
TreeNode childNode = await DirectoryToTreeNodeAsync(dirPath, node);
node.Nodes.Add(childNode);
}
string[] files = await Task.Run(() => Directory.GetFiles(path));
foreach (string filePath in files)
{
node.Nodes.Add(Path.GetFileName(filePath));
}
return node;
}
Notice that no UI control is touched while running on the ThreadPool (inside the Task.Run delegate). All UI controls should be manipulated exclusively by the UI thread.
Usage example:
private async void Button1_Click(object sender, EventArgs e)
{
Button1.Enabled = false;
Cursor = Cursors.WaitCursor;
try
{
TreeView1.Nodes.Clear();
TreeView1.Nodes.Add(
await DirectoryToTreeNodeAsync(#"C:\Users\Tomer\Desktop\a"));
}
finally
{
Cursor = Cursors.Default;
Button1.Enabled = true;
}
}
Here's an example for async Task method to populate a TreeNode with a directory-tree for a given file type. The inner CreateTree(...) is a local function called recursively to traverse the directories.
private async Task<TreeNode> CreateTreeAsync(string startDir, string fileExt)
{
var di = new DirectoryInfo(startDir);
var result = new TreeNode(di.Name);
var searchPattern = $"*.{fileExt.TrimStart('.')}";
return await Task.Run(() =>
{
void CreateTree(DirectoryInfo dirInfo, TreeNode node)
{
try
{
foreach (var fileInfo in dirInfo.EnumerateFiles(searchPattern))
node.Nodes.Add(fileInfo.Name);
foreach (var subDir in dirInfo.EnumerateDirectories())
{
try
{
// Optional to skip the branches with no files at any level.
if (!subDir.EnumerateFiles(searchPattren,
SearchOption.AllDirectories).Any()) continue;
var newNode = new TreeNode(subDir.Name);
node.Nodes.Add(newNode);
CreateTree(subDir, newNode);
}
catch (Exception ex)
{
// Skip exceptions like UnauthorizedAccessException
// and continue...
Console.WriteLine(ex.Message);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
CreateTree(di, result);
return result;
});
}
Note: You don't need the try..catch blocks if you're under .NET 5+/.NET Core to skip the inaccessible directories and files. Use the EnumerateXXX method overload that takes the EnumerationOptions parameter.
Now you need async caller like so:
private async void someButton_Click(object sender, EventArgs e)
{
// Optional...
treeView1.Nodes.Clear();
var dir = #"...";
var ext = "txt";
var node = await CreateTreeAsync(dir, ext);
if (node.Nodes.Count == 0)
MessageBox.Show($"No '{ext}' files were found.");
else
{
treeView1.Nodes.Add(node);
node.Expand();
}
}
I apologize if I'm missing something simple, I'm still learning. This is my first attempt at recursion. this program is supposed to do the following, First I open my FileBrowserDialog, then the listview Populates with the file names within the folder selected. However, when I select the folder it fills the listview but I cannot see any names and my listview freezes. the reason I know it fills is the scroll bar adjusts. this is my code:
#region FileHandlers
void FolderSearch(string sFol)
{
try
{
foreach (string d in Directory.GetDirectories(sFol))
{
foreach (string f in Directory.GetFiles(d))
{
listView1.Items.Add(f);
}
FolderSearch(d);
}
}
catch (System.Exception excpt)
{
MessageBox.Show(excpt.Message);
}
}
public void ChooseFolder()
{
string pPath;
if(folderBrowserDialog1.ShowDialog() == DialogResult.OK)
{
pPath = folderBrowserDialog1.SelectedPath;
FolderSearch(pPath);
}
}
#endregion
void Button1Click(object sender, EventArgs e)
{
ChooseFolder();
}
Your code skips the selected folder and it will only get files from subfolders within selected folder, because you are first calling GetDirectories method, if you don't have subfolders within selected folder or your subfolders dont have files, it will get nothing.
Try this
void FolderSearch(string sFol)
{
try
{
foreach (string f in Directory.GetFiles(sFol))
{
listView1.Items.Add(f);
}
foreach (string d in Directory.GetDirectories(sFol))
{
FolderSearch(d);
}
}
catch (System.Exception excpt)
{
MessageBox.Show(excpt.Message);
}
}
and also if you want only file name use GetFileName method from System.IO.Path class. listView1.Items.Add(Path.GetFileName(f));
I have a small application that watches a specific file and whenever it changes, my application should do the actions in the loop, but something is firing the function more than once!! here's my code
private void OnChanged(object source, FileSystemEventArgs e)
{
if (e.FullPath == #"C:\test.txt")
{
string textFilePath = #"C:\test.txt";
try
{
using (var streamReader = File.OpenText(textFilePath))
{
var lines = streamReader.ReadToEnd().Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
//actions here
}
}
}
catch (Exception)
{
}
}
}
So I'm guessing in the loop when streamreader do File.OpenText somehow is firing the function again?! any ideas?
From MSDN:
The Changed event is raised when changes are made to the size, system attributes, last write time, last access time, ...
So yes, opening (actually: closing) the file will raise the Changed event again.
You can use the NotifyFilter to limit the actions your watcher triggers on.
SOLUTION
So I did one small thing that controlled the issue, I added a counter and always check if it's not the first time, skip and reassign it to 0.
private int fireCounter = 0;
private void OnChanged(object source, FileSystemEventArgs e)
{
fireCounter++;
if (fireCounter == 1)
{
delete();
if (e.FullPath == #"C:\test.txt")
{
Thread.Sleep(2000);
//I added Sleep for two seconds because without it sometimes it wont work
string textFilePath = #"C:\test.txt";
try
{
using (var streamReader = File.OpenText(textFilePath))
{
var lines = streamReader.ReadToEnd().Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
//Actions Here
}
}
}
catch (Exception)
{
}
}
}
else
{
fireCounter = 0;
}
}
Hi guys I have this app that does printing based on items on a listbox.
by commatching those items with that in a directory :\slim\slimyyyy
I want to put an "ERROR CHECKING" that would give me a message that in item
on the listbox is not present in the directory .
For instance if there are 8 items or more is not in the said directory give message with the item thats not in the directory.
Find below is my code ,but my try catch does nothing.Any help is very welcome
Thanks in advance.
{
//var printList = new List();
try
{
var printList = new List();
string dir = #"C:\slim\slimyyyy";
if (Directory.Exists(dir))
{
string[] pdf_specFiles = Directory.GetFiles(dir);
if (pdf_specFiles.Length > 0)
{
foreach (object item in listBox1.Items)
{
foreach (string file in pdf_specFiles)
{
string fileName = Path.GetFileName(file);
if (fileName == item.ToString())
{
printList.Add(Path.GetFullPath(file));
}
}
}
foreach (string file in printList)
{
PrintDocument(file);
System.Threading.Thread.Sleep(10000); // wait 10 second say
Application.DoEvents(); // keep UI responsive if Windows Forms app
}
}
}
}
catch (Exception)
{
MessageBox.Show("You are missing Item(s).", "ERROR");
}
}>
Here's the new solution:
- Please put using System.Linq on top of form
private void Form1_Load(object sender, System.EventArgs e)
{
const string directoryPath = #"C:\slim\slimyyyy";
var printList = new List<string>();
foreach (string item in listBox1.Items)
{
var currentFilePath = Path.Combine(directoryPath, item);
if (File.Exists(currentFilePath))
{
printList.Add(item);
}
}
if (!printList.Any())
{
MessageBox.Show("File doesn't exist");
return;
}
foreach (string file in printList)
{
PrintDocument(file);
// Why you want to wait?? Let it print.
}
}
I'm very new to C#. I'm populating a File Explorer using C#. What i want to do now is implementing the listView1_MouseDoubleClick() method so that when I double-click in a sub folder, the current listView will be cleared then it will display files and folders in that subfolders (like what Windows Explorer does). Here's my code:
private void listView1_MouseDoubleClick(object sender, MouseEventArgs e)
{
for (int i = 0; i < listView1.Items.Count; i++)
{
if (listView1.Items[i].Selected == true)
{
string path = listView1.Items[i].Name;
comboBox1.Text = path;
listView1.Items.Clear();
LoadFilesAndDir(path);
}
}
}
private void LoadFilesAndDir(string address)
{
DirectoryInfo di = new DirectoryInfo(address);
try
{
foreach (FileInfo fi in di.GetFiles())
{
listView1.Items.Add(fi.Name);
}
try
{
foreach (DirectoryInfo listd in di.GetDirectories())
{
listView1.Items.Add(listd.FullName, listd.Name, 0);
}
}
catch (Exception e1)
{
}
}
catch (Exception e1)
{
}
}
But it failed to run. When I debug this error step by step, I found out that after this statement: path = listView1.Items[i].Name; the path variable's value is "". So i guess that the reason which let to the error. But I don't know how to fix that... Could you guys help me with this ? Thanks a lot in advanced !
Make sure that you declare the string 'path' first
string path = "";
Then insert this code:
private void listView1_MouseDoubleClick(object sender, EventArgs e)
{
for (int i = 0; i < listView1.Items.Count; i++)
{
if (listView1.Items[i].Selected == true)
{
path = Convert.ToString(listView1.Items[i]);
// This replaces the part "List View Item: {"
path = path.Replace("ListViewItem: {", "");
// This replaces the part "}"
path = path.Replace("}", "");
comboBox1.Text = path;
listView1.Items.Clear();
LoadFilesAndDir(path);
}
}
}
The code is a bit long, but it works!