I add some files to a listbox on a button:
if (Directory.Exists(DirString))
{
DirectoryInfo dirETC = new DirectoryInfo(DirString);
FileInfo[] Files = dirETC.GetFiles("*.txt");
foreach (FileInfo file in Files)
{
listBox1.Items.Add(file.FullName);
}
If user clicks the delete button, i would like to delete all files in the listbox like this:
try
{
listBox1.BeginUpdate();
for (int i = 0; i < listBox1.Items.Count; i++)
{
string filename = listBox1.Items[i].ToString();
if (File.Exists(filename))
{
File.Delete(filename);
listBox1.Items.Remove(filename);
}
}
listBox1.EndUpdate();
}
catch (Exception)
{
return;
}
The above code works, but its only deleting one file every time i click the delete all button. I think I need to add some kind of foreach loop here to iterate through the items but i'm not sure what is the best way to go about it.
Foreach statement won't allow you to modify a collection you are iterating through, while for will. You just have to be careful with indexes: in your solution after removing the first item (with index=0) the next one become first. Try this approach instead:
listBox1.BeginUpdate();
for (int i = listBox1.Items.Count - 1; i >=0; i--)
{
string filename = listBox1.Items[i].ToString();
if (File.Exists(filename))
{
try
{
File.Delete(filename);
listBox1.Items.Remove(filename);
}
catch (Exception)
{
}
}
}
listBox1.EndUpdate();
When you remove an item from an array that you are iterating over with the for..next statement, you should consider that every time you delete an element, the array count decrease of one element and every element in the array shifts at a lower index. So, when you delete the element at index 0, the previous element that were at index 1 shifts in position 0, but you have already iterated over the index zero, so you end skipping that element and trying to delete the element that was at index 2 before the removal of the item at index 0.
The solution is simple. Loop in reverse order (from highest element to lowest)
for (int i = listBox1.Items.Count-1; i >= 0 ; i--)
{
string filename = listBox1.Items[i].ToString();
if (File.Exists(filename))
{
File.Delete(filename);
listBox1.Items.Remove(filename);
}
}
Copy the contents of the listbox into a string array to prevent errors when remove the items from the listbox in looping.
// Copy the contents of the listbox into a string array
string[] filenameList = listBox1.Items.OfType<string>().ToArray();
try
{
for (int i = 0; i < filenameList.Length; i++)
{
string filename = filenameList[i];
if (File.Exists(filename))
{
File.Delete(filename);
listBox1.Items.Remove(filename);
}
}
}
catch (Exception)
{
}
Related
I have a main List of Files Filelist.The Main List Contains Full File Paths and there is a second list copylist it is poupulated by fetching the contents from a directory.I need to replace the File Names in Filelist that matches with the ones in the temporary folder,so i used the following code.
Filelist = new List<string>();
//Code to Populate File List from openfiledialog
try
{
copylist = Directory.GetFiles(temppath + #"\mydir\");
List<string> tempfiles = new List<string>(Filelist);
int x = 0;
foreach (string file in tempfiles)
{
for (int i = 0; i < copylist .Length; i++)
{
if (Path.GetFileName(file) == Path.GetFileName(copylist [i]))
{
MessageBox.Show("Removed: " + file + " \ninserted:" + copylist [i]);
Filelist.RemoveAt(x);
Filelist.Insert(x,copylist [i]);
}
x++;
}
}
}
catch (Exception)
{
}
I tested with 4 files... The File names matched when i checked manually(ie: the same file name in temp folder and in the FileList).The equality check ie:Path.GetFileName(file) == Path.GetFileName(copylist [i]) is satisfied for just 2 files and finally only 1 file is replaced in Filelist even though all 4 files are present in temp folder.
What im i doing wrong.Please advice.
The logic of your program relies on the fact that positions in tempfiles and Filelist are related, and that x corresponds to the position of file in tempfiles. In order for this to work you need to add a break inside the if, and move x++ to the outside loop:
foreach (string file in tempfiles) {
for (int i = 0; i < copylist .Length; i++) {
if (Path.GetFileName(file) == Path.GetFileName(copylist [i])) {
MessageBox.Show($"Removed: {file}\ninserted:{copylist [i])}";
Filelist.RemoveAt(x);
Filelist.Insert(x,copylist[i]);
break; // << Added
}
}
x++; // << Moved
}
for (int i = 0; i < BackgroundWorkerConfiguration.urlsDirectories.Count; i++)
{
file_array =Directory.GetFiles(BackgroundWorkerConfiguration.urlsDirectories[i]);
}
DateTime[] creationTimes8 = new DateTime[file_array.Length];
for (int i = 0; i < file_array.Length; i++)
creationTimes8[i] = new FileInfo(file_array[i]).CreationTime;
Array.Sort(creationTimes8, file_array);
file_indxs = 0;
file_indxs = file_array.Length - 1;
timer1.Enabled = true;
urlsDirectories contain 5 directories in which you have a directory on each index.
In each directory there are some files. I have a string Array file_array. The Array I get, file_array at the end of the loop only contains the last directory file and not all the files. I need all the files in that specific directory.
Once that is done, I need to check if the file sizes are greater than 0, and if It is satisfying the condition then continue on.
EDIT** this is the timer1 tick event:
private void timer1_Tick(object sender, EventArgs e)
{
try
{
//this.pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
if (leave == true)
{
pb.Load(file_array[file_indxs]);
}
else
{
pbs[0].Load(file_array[file_indxs]);
}
file_indxs = file_indxs - 1;
if (file_indxs < 0)
{
file_indxs = file_array.Length - 1;
}
}
catch
{
timer1.Enabled = false;
}
}
You can use the following code to get the files with size greater than 0 for all directories into a List:
List<System.IO.FileInfo> fileList = new List<System.IO.FileInfo>();
for (int i = 0; i < BackgroundWorkerConfiguration.urlsDirectories.Count; i++)
{
System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(BackgroundWorkerConfiguration.urlsDirectories[i]);
fileList.AddRange(di.GetFiles("*.*", System.IO.SearchOption.AllDirectories).Where(x => x.Length > 0));
}
Now fileList will contain the list of FileInfo which you can use further in your code.
Please note that I used System.IO.SearchOption.AllDirectories to search in all subdirectories as well - I'm not sure if you need it or not.
You can use the following code to sort the list of files by creation date and convert it to a array of file names:
String[] file_array = fileList.OrderBy(x => x.CreationTime).Select(x => x.FullName).ToArray();
If you want to sort in the descending order, you can use
String[] file_array = fileList.OrderByDescending(x => x.CreationTime).Select(x => x.FullName).ToArray();
You can make a recursive function that gets the files from a directory.
void GetFiles(string directory, ref List<string> directories)
{
var tempFiles = Directory.EnumerateFiles(directory);
var tempDirs = Directory.EnumerateDirectories(directory);
foreach (var x in tempFiles)
directories.Add(x);
foreach (var x in tempDirs)
GetFiles(x, ref directories);
}
This would obtain all the files from a folder and its subfolders. You can then obtain the data for the files you have enumerated.
This piece of code takes a row from 1.txt and splits it into columns. Now I have a directory of 200 + files with ending something.txt and I want them all to open one at a time and this process below run . What is the easiest way to loop thro all the files without changing my code too much ?
Snippet of code currently ;
string _nextLine;
string[] _columns;
char[] delimiters;
delimiters = "|".ToCharArray();
_nextLine = _reader.ReadLine();
string[] lines = File.ReadAllLines("C:\\P\\DataSource2_W\\TextFiles\\Batch1\\1.txt");
//Start at index 2 - and keep looping until index Length - 2
for (int i = 3; i < lines.Length - 2; i++)
{ _columns = lines[i].Split('|');
// Check if number of cols is 3
if (_columns.Length == 146)
{
JazzORBuffer.AddRow();
JazzORBuffer.Server = _columns[0];
JazzORBuffer.Country = _columns[1];
JazzORBuffer.QuoteNumber = _columns[2];
JazzORBuffer.DocumentName =_columns[3];
JazzORBuffer.CompanyNameSoldTo=_columns[4];
}
else
{
// Debug or messagebox the line that fails
MessageBox.Show("Cols:" + _columns.Length.ToString() + " Line: " + lines[i]);
return;
}
}
You can simply use Directory.EnumerateFiles() to iterate over the files colection of the specified directory.
So you can insert your code inside foreach loop, like:
foreach (var file in
Directory.EnumerateFiles(#"C:\\P\\DataSource2_W\\TextFiles\\Batch1", "*.txt"))
{
//your code
}
I am checking if a file exists, and if it does, I put it in a list, otherwise I remove from the list. My code is so:
foreach (KeyValuePair<string, string> kvp in dict)
{
_savedxml.Add(kvp.Key.ToString());
}
string namewithext=null;
for (int i = 0; i < _savedxml.Count; i++)
{
namewithext = string.Concat(_savedxml[i], ".xml");
System.IO.FileInfo file_info = new System.IO.FileInfo((string)namewithext);
long size = file_info.Length;
if (size == 0)
{
_savedxml.RemoveAt(i);
}
}
for (int i = 0; i < _savedxml.Count; i++)
{
if (System.IO.File.Exists(System.IO.Path.GetFullPath(namewithext)))
{
}
else
{
_savedxml.Remove(namewithext);
}
}
I've tried many ways, but even though a file does not exist, the list contains it. I've probably made a silly error.
How can I do this?
There are several errors in the code:
You set the namewithext variable for each item in the first loop, then use it in the second loop, so you will be checking if the last file exist over and over.
When you remove an item, the next item takes its place in the list, so you will skip the check for the next item.
You are checking the length of the files before checking if the files exist, so you will get a FileNotFoundException when you try to get the length for files that doesn't exist.
Corrected (and some cleanup):
foreach (KeyValuePair<string, string> kvp in dict) {
_savedxml.Add(kvp.Key);
}
for (int i = _savedxml.Count - 1; i >= 0 ; i--) {
string namewithext = _savedxml[i] + ".xml";
if (!System.IO.File.Exists(System.IO.Path.GetFullPath(namewithext))) {
_savedxml.RemoveAt(i);
}
}
for (int i = _savedxml.Count - 1; i >= 0 ; i--) {
string namewithext = _savedxml[i] + ".xml";
System.IO.FileInfo file_info = new System.IO.FileInfo(namewithext);
if (file_info.Length == 0) {
_savedxml.RemoveAt(i);
}
}
There are two problems with your code that I can spot:
Getting the Length property of a FileInfo instance that refers to a file that doesn't exist should throw an exception, not return 0.
In the second for-loop you iterate over your savedxml list, yet you never change the "namewithext"-variable, which would cause you to try and remove the same entry every time.
EDIT
Additionally, Duncan is right, of course, if the code inside the "if (size == 0)" branch would ever run, you'd skip an entry in your list.
You're removing an item from your collection by index, which will then change the position of the remaining items in your collection. It will then end up skipping an entry which it should have removed.
_savedxml has file names without extesnion, so before _savedxml.Remove(namewithext); remove extesnion from namewithext.
foreach (KeyValuePair<string, string> kvp in dict)
{
_savedxml.Add(kvp.Key.ToString());
}
string namewithext = null;
int i = 0;
while (i < _savedxml.Count)
{
namewithext = string.Concat(_savedxml[i], ".xml");
System.IO.FileInfo file_info = new System.IO.FileInfo((string)namewithext);
if (!file_info.Exists || file_info.Length == 0)
_savedxml.RemoveAt(i);
else
i++;
}
if i have 4 files. and i want to move half of them to disc 1 and half of them to disc 2.
if im using the:
Directory.Move(source, destination)
im guessing i can change to source by doing a foreach loop + an array or list,
but how could i change the destination after half the source files are transfered and then transfer the other half to the new destination?
string[] files = ... // create a list of files to be moved
for (int i = 0; i < files.Length; i++)
{
var sourceFile = files[i];
var destFile = string.Empty;
if (i < files.Length / 2)
{
destFile = Path.Combine(#"c:\path1", Path.GetFileName(sourceFile));
}
else
{
destFile = Path.Combine(#"d:\path2", Path.GetFileName(sourceFile));
}
File.Move(sourceFile, destFile);
}
UPDATE:
Here's a lazy approach which doesn't require you to load all the file names in memory at once which could be used for example in conjunction with the Directory.EnumerateFiles method:
IEnumerable<string> files = Directory.EnumerateFiles(#"x:\sourcefilespath");
int i = 0;
foreach (var file in files)
{
var destFile = Path.Combine(#"c:\path1", Path.GetFileName(file));
if ((i++) % 2 != 0)
{
// alternate the destination
destFile = Path.Combine(#"d:\path2", Path.GetFileName(file));
}
File.Move(sourceFile, destFile);
}
The simple answer is that you would move the individual files instead.
Use a Directory.GetFiles(source) to get a list of files in the folder, get a .Count() of that and then loop through each file and move it.
public void MoveFilesToSplitDestination(string source, string destination1, string destination2)
{
var fileList = Directory.GetFiles(source);
int fileCount = fileList.Count();
for(int i = 0; i < fileCount; i++)
{
string moveToDestinationPath = (i < fileCount/2) ? destination1 : destination2;
fileList[i].MoveTo(moveToDestination);
}
}
int rubikon= files.Count() / 2;
foreach (var file in files.Take(rubikon))
file.Move(/* first destination */));
foreach (var file in files.Skip(rubikon))
file.Move(/* second destination */));