I have a simple program that copies files and directories from one place to another. I have it set-up that if there are any exceptions (such as if access to the path is denied) it will create a log file with the error.
I have a button that when pressed, performs the copy action. Everything works fine the first time I press the button and the log file is either created or overwritten with the appropriate error messages.
However, if I press the button a second time, the text file is not overwritten and instead the error messages append. If I close out of my program and run it again, the file is overwritten on the first button press. Any thoughts would be greatly appreciated.
target is a string filepath which I'm getting from a FolderBrowserDialog and taking the selected path and setting it to a textbox. loglist is just a simple List<string> I'm using to store the error messages from any exceptions that occur during the copy process.
public partial class Form1 : Form
{
static List<string> logList = new List<string>();
public Form1()
{
InitializeComponent();
}
private static void CopyAll(DirectoryInfo source, DirectoryInfo target)
{
if (source.FullName.ToLower() == target.FullName.ToLower())
return;
if (Directory.Exists(target.FullName) == false)
{
Directory.CreateDirectory(target.FullName);
}
foreach (FileInfo fi in source.GetFiles())
{
try
{
fi.CopyTo(Path.Combine(target.ToString(), fi.Name), true);
}
catch (Exception ex)
{
logList.Add(ex.Message);
}
}
foreach (DirectoryInfo diSourceSub in source.GetDirectories())
{
DirectoryInfo nextTargetSubDir = target.CreateSubdirectory(diSourceSub.Name);
CopyAll(diSourceSub, nextTargetSubDir);
}
}
private void directoryPickerBtn1_Click(object sender, EventArgs e)
{
FolderBrowserDialog folderDialog = new FolderBrowserDialog();
DialogResult folderResult = folderDialog.ShowDialog();
if (folderResult == DialogResult.OK)
{
directoryTextbox1.Text = folderDialog.SelectedPath;
}
}
private void directoryPickerBtn2_Click(object sender, EventArgs e)
{
FolderBrowserDialog folderDialog = new FolderBrowserDialog();
DialogResult folderResult = folderDialog.ShowDialog();
if (folderResult == DialogResult.OK)
{
directoryTextbox2.Text = folderDialog.SelectedPath;
}
}
private void copyBtn_Click(object sender, EventArgs e)
{
string source = (directoryTextbox1.Text);
string target = (directoryTextbox2.Text);
DirectoryInfo dirSource = new DirectoryInfo(source);
DirectoryInfo dirTarget = new DirectoryInfo(target);
try
{
CopyAll(dirSource, dirTarget);
if (logList.Count > 0)
{
using (StreamWriter sw = new StreamWriter(target + #"\log.txt", false))
{
foreach (string error in logList)
{
sw.WriteLine(error);
}
}
}
DialogResult result = MessageBox.Show("Copy Succeeded", "Success");
if (result == DialogResult.OK)
{
string myPath = dirTarget.ToString();
System.Diagnostics.Process prc = new System.Diagnostics.Process();
prc.StartInfo.FileName = myPath;
prc.Start();
}
}
catch (Exception)
{
MessageBox.Show("Copy Failed", "Failed");
}
}
}
}
As #Reza Aghaei pointed out in comments, the problem is that you do not clear the logList.
The file gets created anew every time, but each time you click the Copy button, the loglist still contains the results of the previous copy action.
So you need to clear the list when starting a new copy:
private static void CopyAll(DirectoryInfo source, DirectoryInfo target)
{
logList.Clear();
// ...
From your code it seems that you never clear the logList, this means that it appears the file is being appending because the logList still contains all of the old entries.
You'll need to clear the list between copies if you only want relevant entries to that copy, either before you start copying or after you finish writing the file.
This would be better as a separate method
try
{
CopyAll(dirSource, dirTarget);
SaveLog(target + #"\log.txt");
ClearLog();
//...
}
private void SaveLog(string filename)
{
if (logList.Count > 0)
{
FileStream fs = File.Open(target + #"\log.txt", FileMode.Create);
using (StreamWriter sw = new StreamWriter(fs))
{
foreach (string error in logList)
{
sw.WriteLine(error);
}
}
}
}
Related
As you can see in code, folders are created during move file button. my question is that how to moves files in that particular folders, I have tens of millions of files and want to moves in that particulars. I am new in c#.
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace File2Folders
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
List<string> fileName = null;
List<string> fileNames = null;
private void btn_browse_Click(object sender, EventArgs e)
{
using (FolderBrowserDialog fbd = new FolderBrowserDialog())
{
if (fbd.ShowDialog() == DialogResult.OK)
{
listBox1.Items.Clear();
fileName = Directory.GetFiles(fbd.SelectedPath).ToList();
fileNames = fileName.Select(item => Path.GetFileNameWithoutExtension(item).Substring(1, 4)).OrderBy(n=>n).ToList();
listBox1.DataSource = fileName.Select(f => Path.GetFileName(f)).ToList();
listBox2.DataSource = fileNames;
}
}
}
private void btn_move_Click(object sender, EventArgs e)
{
using (FolderBrowserDialog fbd = new FolderBrowserDialog())
{
if (fbd.ShowDialog() == DialogResult.OK)
{
fileNames.ForEach(item => Directory.CreateDirectory(Path.Combine(fbd.SelectedPath, item)));
}
Try to use this fuction that I use sometimes.
bool FileCopyPasteRename(string source, string destination, string renameTo)
{
bool res = false;
string renameDestination = Path.Combine(destination, renameTo.ToLower());
try
{
if (File.Exists(source))
{
File.Copy(source, renameDestination, true);
}
}
catch (Exception ex)
{
//cath error ex.Message
}
return res;
}
Once its a bool function, you can check if returns true and the delete source file.
To move a file you can use method Move in File. It takes as parameter the path of the file you want to move and the destination including and the file name
here is an example
string filePath = #"C:\Users\HP\source\repos\ConsoleApp1\ConsoleApp1\fileToMove.txt";
string destination = #"C:\Users\HP\source\repos\ConsoleApp1\ConsoleApp1\Dummy\fileToMove.txt";
try
{
File.Move(filePath, destination);
}
catch (Exception e)
{
Console.WriteLine("We coudnt move the file becouse of: " + e.Message);
}
For more https://learn.microsoft.com/en-us/dotnet/api/system.io.file.move?view=net-6.0
I am having a problem with a with a code that I used for my C# application. When I click on the browse button and select the file dialogue box opens twice.
private void txt_location_TextChanged(object sender, EventArgs e)
{
string folderPath = "";
FolderBrowserDialog folderBrowserDialog1 = new FolderBrowserDialog();
if (folderBrowserDialog1.ShowDialog() == DialogResult.OK) {
folderPath = folderBrowserDialog1.SelectedPath;
}
}
private void Button21_Click(object sender, EventArgs e)
{
using(var fbd = new FolderBrowserDialog()) {
DialogResult result = fbd.ShowDialog();
if (result == DialogResult.OK && !string.IsNullOrWhiteSpace(fbd.SelectedPath)) {
selectedPath = fbd.SelectedPath;
txt_location.Text = selectedPath;
}
}
}
private void bunifuThinButton21_Click_1(object sender, EventArgs e)
{
System.IO.StreamWriter file;
bool isvalid = ValidateInputs();
try {
file = new System.IO.StreamWriter(selectedPath + # "\dred.txt");
catch (Exception ex) {
MessageBox.Show("Please, Select valid Path..");
return;
}
try {
if (isvalid) {
WriteLines(file);
}
}
catch (Exception ex2) {
MessageBox.Show(ex2.Message);
}
finally {
file.Close();
}
}
}
Obviously, it is only meant to open once to enable me to read the selected file. This works, but only once I have selected the file twice.
Thanks in advance for your help.
You have FolderBrowserDialog being instantiated and shown on two different events:
txt_location_TextChanged
and
Button21_Click
You're having two popups because each one is firing once separately.
You should probably remove the event txt_location_TextChanged entirely unless you need it for another thing that isn't popping the FolderBrowserDialog again.
I have a listbox that displays the names of the files that are opened either with a dragDrop functionality or with an OpenFileDialog, the file paths are stored in the List named playlist, and the listbox only displays the names without paths and extensions. When my form closes, the playlist content is saved to a .txt file. When I open again my application, the content in the text file is stored again in the listbox and the playlist. But when I add new files after re-opening the form, I don't know why it leaves a blank line between the last files and the recently added ones.
This is the code I use to WRITE the content of playlist(List) in the txt file:
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
if(listBox1.Items.Count > 0)
{
StreamWriter str = new StreamWriter(Application.StartupPath + "/Text.txt");
foreach (String s in playlist)
{
str.WriteLine(s);
}
str.Close();
}
This is the code used to READ the same txt file:
private void Form1_Load(object sender, EventArgs e) //Form Load!!!
{
FileInfo info = new FileInfo(Application.StartupPath + "/Text.txt");
if(info.Exists)
{
if (info.Length > 0)
{
System.IO.StreamReader reader = new System.IO.StreamReader(Application.StartupPath + "/Text.txt"); //StreamREADER
try
{
do
{
string currentRead = reader.ReadLine();
playlist.Add(currentRead);
listBox1.Items.Add(System.IO.Path.GetFileNameWithoutExtension(currentRead));
} while (true);
}
catch (Exception)
{
reader.Close();
listBox1.SelectedIndex = 0;
}
}
else
{
File.Delete(Application.StartupPath + "/Text.txt");
}
}
else
{
return;
}
}
The code used to add files to listbox and playlist:
OpenFileDialog ofd = new OpenFileDialog();
ofd.Title = "Select File(s)";
ofd.Filter = "Audio Files (*.mp3, *.wav, *.wma)|*.mp3|*.wav|*.wma";
ofd.InitialDirectory = "C:/";
ofd.RestoreDirectory = false;
ofd.Multiselect = true;
ofd.ShowDialog();
foreach (string s in ofd.FileNames)
{
listBox1.Items.Add(Path.GetFileNameWithoutExtension(s));
playlist.Add(s);
}
listBox1.SelectedIndex = 0;
This is what I get when I add new files after re-opening my form:
Thanks in advance, I hope StackOverflow community can help me!
First of all: debug your code and you'll find the problem yourself :)
Issue is the use of the WriteLine method. The last line you write should use the Write method instead so that you don't have an empty line at the end. Alternatively and easier to implement is to only add non-empty lines to your playlist such like this:
// ...
do
{
string currentRead = reader.ReadLine();
if (!string.IsNullOrWhiteSpace(currentRead)) // ignore empty lines
{
playlist.Add(currentRead);
listBox1.Items.Add(System.IO.Path.GetFileNameWithoutExtension(currentRead));
}
} while (true);
As a side comment: while (true) and using exception handling is a bad approach to end a loop.
the following code is reading all files Contain in the subfolders and in the folders.
But I need to write all files Contain in the subfolders and in the folders in to .txt file.
Can any one say me how do change it .
private void btnSearchNow_Click(object sender, EventArgs e)
{
BLSecurityFinder lSecFinder = new BLSecurityFinderClass();
int iCounter = 0;
lbselected.Items.Clear();
lSecFinder.bScanSubDirectories = chkSubfolders.Checked;
try
{
lSecFinder.FindSecurity(txtSymbol.Text, txtDirectory.Text);
while (lSecFinder.bSecLeft)
{
// Insert(iCounter, lSecFinder.SecName);
lbselected.Items.Add(new SampleData() { Name = lSecFinder.SecName });
lbselected.DisplayMember = "Name";
lSecFinder.FindNextSecurity();
iCounter++;
}
}
catch (System.Runtime.InteropServices.COMException ComEx)
{
//MessageBox.Show (ComEx.Message);
}
finally
{
lSecFinder.DestroySearchDialog();
}
}
private void btnClose_Click(object sender, EventArgs e)
{
this.Close();
}
thanks in addvance
var searchPattern = "*.*";
var output = #"c:\results.txt";
var files = Directory.GetFiles(folderBrowserDialog1.SelectedPath,
searchPattern,
chkSubfolders.Checked ? SearchOption.AllDirectories:SearchOption.TopDirectoryOnly);
File.WriteAllLines(output, files);
you can use System.IO class library DirectoryInfo and FileInfo class and the logic goes as follows
1) Create two functions on to process directory and one to process file
2) In which directory read function reads validate if the item is file or directory
3) If the item is directory it recursively calls itself 4) If the item is file it send it to file process method for processing
public void fnProcessDirectory(string strPath)
{
if (File.Exists(strPath))
{
fnProcessFile(strPath);
}
else if (Directory.Exists(strPath))
{
string[] fileEntries = Directory.GetFiles(strPath);
string[] subdirEntries = Directory.GetDirectories(strPath);
foreach (string fileName in fileEntries)
{
fnProcessFile(fileName);
}
foreach (string dirName in subdirEntries)
{
fnProcessDirectory(dirName);
}
}
}
public void fnProcessFile(string strPath)
{
//write the file name in the txt file
}
This will get all the folder and sub-folder filesNames.
you can specify the type of file you looking for or * to get every file.
public void File_To_Text(string filepath)
{
string [] fname;
fname = Directory.GetFiles(filepath, "*.*", SearchOption.AllDirectories).Select(x => Path.GetFileName(x)).ToArray();
File.WriteAllLines("c:\\images.txt", fname, Encoding.UTF8);
}
Here is another version which extends your code directly:
private void btnSearchNow_Click(object sender, EventArgs e)
{
BLSecurityFinder lSecFinder = new BLSecurityFinderClass();
int iCounter = 0;
lbselected.Items.Clear();
lSecFinder.bScanSubDirectories = chkSubfolders.Checked;
using (StreamWriter writer = new StreamWriter(#"C:\results.txt", false))
{
try
{
lSecFinder.FindSecurity(txtSymbol.Text, txtDirectory.Text);
while (lSecFinder.bSecLeft)
{
// Insert(iCounter, lSecFinder.SecName);
lbselected.Items.Add(new SampleData() { Name = lSecFinder.SecName });
lbselected.DisplayMember = "Name";
// assuming SecName is the full filename
writer.WriteLine(lSecFinder.SecName);
lSecFinder.FindNextSecurity();
iCounter++;
}
}
catch (System.Runtime.InteropServices.COMException ComEx)
{
//MessageBox.Show (ComEx.Message);
}
finally
{
lSecFinder.DestroySearchDialog();
}
}
}
I have a Windows Form application. What this application does, is let the user browse to a drive/folder they wish to have files renamed for. This app renames files that have "invalid" characters (that are defined in a RegEx pattern).
What i want to happen here is, after the user decides which drive/folder to use, a datagridview pops up showing the user files in the drive/folder that are going to be renamed. The user then clicks a button to actually rename the files. I'm having trouble though getting the code for my button in DriveRecursion_Results.cs set up. Can anybody help me? Code plz -- i'm extremely new to this and need syntax to look at to understand.
Form1 code:
namespace FileMigration2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
FolderSelect("Please select:");
}
public string FolderSelect(string txtPrompt)
{
//Value to be returned
string result = string.Empty;
//Now, we want to use the path information to population our folder selection initial location
string initialPathDir = (#"C:\");
System.IO.DirectoryInfo info = new System.IO.DirectoryInfo(initialPathDir);
FolderBrowserDialog FolderSelect = new FolderBrowserDialog();
FolderSelect.SelectedPath = info.FullName;
FolderSelect.Description = txtPrompt;
FolderSelect.ShowNewFolderButton = true;
if (FolderSelect.ShowDialog() == DialogResult.OK)
{
string retPath = FolderSelect.SelectedPath;
if (retPath == null)
{
retPath = "";
}
DriveRecursion_Results dw = new DriveRecursion_Results();
dw.Show();
dw.DriveRecursion(retPath);
result = retPath;
}
return result;
}
}
}
DriveRecursion_Results.cs code: [the button is in here that i need help with!]
namespace FileMigration2
{
public partial class DriveRecursion_Results : Form
{
public DriveRecursion_Results()
{
InitializeComponent();
}
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
}
public void DriveRecursion(string retPath)
{
//recurse through files. Let user press 'ok' to move onto next step
// string[] files = Directory.GetFiles(retPath, "*.*", SearchOption.AllDirectories);
string pattern = " *[\\~#%&*{}/<>?|\"-]+ *";
//string replacement = "";
Regex regEx = new Regex(pattern);
string[] fileDrive = Directory.GetFiles(retPath, "*.*", SearchOption.AllDirectories);
List<string> filePath = new List<string>();
dataGridView1.Rows.Clear();
try
{
foreach (string fileNames in fileDrive)
{
if (regEx.IsMatch(fileNames))
{
string fileNameOnly = Path.GetFileName(fileNames);
string pathOnly = Path.GetDirectoryName(fileNames);
DataGridViewRow dgr = new DataGridViewRow();
filePath.Add(fileNames);
dgr.CreateCells(dataGridView1);
dgr.Cells[0].Value = pathOnly;
dgr.Cells[1].Value = fileNameOnly;
dataGridView1.Rows.Add(dgr);
filePath.Add(fileNames);
}
else
{
DataGridViewRow dgr2 = new DataGridViewRow();
dgr2.Cells[0].Value = "No Files To Clean Up";
dgr2.Cells[1].Value = "";
}
}
}
catch (Exception e)
{
StreamWriter sw = new StreamWriter(retPath + "ErrorLog.txt");
sw.Write(e);
}
}
private void button1_Click(object sender, EventArgs e)
{
//What do i type in here to call my FileCleanUp method???
}
}
SanitizeFileNames.cs code:
namespace FileMigration2
{
public class SanitizeFileNames
{
public static void FileCleanup(List<string>filePath)
{
string regPattern = "*[\\~#%&*{}/<>?|\"-]+*";
string replacement = "";
Regex regExPattern = new Regex(regPattern);
foreach (string files2 in filePath)
{
try
{
string filenameOnly = Path.GetFileName(files2);
string pathOnly = Path.GetDirectoryName(files2);
string sanitizedFileName = regExPattern.Replace(filenameOnly, replacement);
string sanitized = Path.Combine(pathOnly, sanitizedFileName);
//write to streamwriter
System.IO.File.Move(files2, sanitized);
}
catch (Exception ex)
{
//write to streamwriter
}
}
}
}
}
}
Any help is appreciated!
Thanks :)
Put
public partial class DriveRecursion_Results : Form {
List<string> filePath;
and in driveRecursion method, just use
filePath = new List<string>();
and in the action button method, why don't you do
if(filePath != null)
SanitizeFileNames.FileCleanup(filePath);
You call filePath.Add twice ?
Your 'else' is in the wrong place too.
What is dgr2?