I hve a small code which can rename all files (picture) in a folder and it looks like this:
static void Main(string[] args)
{
try
{
DirectoryInfo d = new DirectoryInfo(#"C:\Users\filip_000\Pictures\Prag");
int i = 1;
foreach (var file in d.GetFiles())
{
Directory.Move(file.FullName, #"C:\Users\filip_000\Pictures\Prag\" + "Prag_" + i.ToString() + ".jpg");
i++;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
It works fine, but I would like to rename the pictures (Prag_1, Prag_2, Prag_3...) according to date/time of the file. I mean: the first picture I made on 25.03.2016 16:04 should be "Prag_1" and the last picture I took on 27.03.2016 19:19 should be "Prag_n".
I hope I could explain my issue. Thank you for helping.
Filippo.
Order files on LastWriteTime and then move.
foreach (var file in d.GetFiles().OrderBy(f => f.LastWriteTime))
{
Directory.Move(file.FullName, #"C:\Users\filip_000\Pictures\Prag\" + "Prag_" + i.ToString() + ".jpg");
i++;
}
OrderBy CreationTime property can be good choice:
foreach (var file in d.GetFiles().OrderBy(f => f.CreationTime))
{
Directory.Move(file.FullName, #"E:\MP3 #1\Prag\" + "Prag_" + i.ToString() + ".jpg");
i++;
}
Related
Here is all I want to do: Every time the button is clicked, an openfile dialog is opened, the user clicks on a picture, then this picture is copied to a specific folder and renamed to a number. Every picture's name in this folder should be a number, but they must all be different. My code so far:
if (openfile.ShowDialog() == DialogResult.OK)
{
try
{
File = Image.FromFile(openfile.FileName);
pictureBox3.Image = File;
int i = 0;
if (System.IO.File.Exists(picturedir + "\\" + i.ToString() + ".png") == true)
{
i++;
MessageBox.Show(picturedir + "\\" + i.ToString() + ".png" + ".....Already Exists.");
}
else if (System.IO.File.Exists(picturedir + "\\" + i.ToString() + ".png") == false)
{
System.IO.File.Copy(openfile.FileName, picturedir + "\\" + i.ToString() + ".png", true);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Of course here, the first picture is copied and renamed to "0.png" but the next pictures are not copied at all, because the "if" gives true. Any ideas ? Thanks.
You could do this:
...
int i = 0;
while (System.IO.File.Exists(picturedir + "\\" + i.ToString() + ".png") == true)
{
i++;
// I wouldn't show that message each time, gonna get pretty old for lots of pics!
}
System.IO.File.Copy(openfile.FileName, picturedir + "\\" + i.ToString() + ".png", true);
...
If you want the next number, you can enumerate the existing files, find the maximum number now in use and add 1. Something like:
var files = Directory.EnumerateFiles(myCurrentDirectory, "*.png");
var fileNumStrings = from file in files select Path.GetFileNameWithoutExtension(file);
var max = 0;
foreach (var fileNumString in fileNumStrings)
{
if (int.TryParse(fileNumString, out var filenum))
{
if (filenum > max)
{
max = filenum;
}
}
}
var nextNum = max + 1;
I'm making a program that writes a list of student objects to a text file and needs to be saved, I could either simply overwrite the contents of the file or delete the contents and rewrite the new list. This is the code I've tried using after some searching,
private void saveTSMI_Click(object sender, EventArgs e)
{
if (lstStudNames.Items.Count != 0)
{
SaveFileDia.Filter = "Text Files | *.txt";
if (SaveFileDia.ShowDialog() == DialogResult.OK)
{
//Clear the file
File.WriteAllText(SaveFileDia.FileName, string.Empty);
//Put all the student info into a string
foreach (Stud student in StudentList)
{
StudentInfoHolder += "Name: " + student.Name + Environment.NewLine +
"Subject: " + student.Subject + Environment.NewLine +
"Age: " + student.age + Environment.NewLine +
"Grade: " + student.Grade + Environment.NewLine
+ Environment.NewLine;
}
Clipboard.SetText(StudentInfoHolder);
File.WriteAllText(SaveFileDia.FileName, StudentInfoHolder);
}
}
else
{
MessageBox.Show("Nothing to save");
}
I've seen that File.WriteAllText() is meant to overwrite the file but nothing is overwritten when the program is saved.
You have to either reset the StudentInfoHolder class member before the foreach loop, or even better, use a local string variable in combination with String.Format method like this:
string studentInfoHolder;
foreach (Stud student in StudentList)
{
studentInfoHolder +=
string.Format("Name: {0}\r\nSubject: {1}\r\nAge: {2}\r\nGrade: {3}",
student.Name, student.Subject, student.age, student.Grade);
}
File.WriteAllText(SaveFileDia.FileName, studentInfoHolder);
Also, you're right that File.WriteAllText overwrites the file content, so this line is useless:
File.WriteAllText(SaveFileDia.FileName, string.Empty);
Update
As #kevin correctly pointed out, it is more efficient to use StringBuilder in the loop instead of the string concatenation:
StringBuilder studentInfoHolder;
foreach (Stud student in StudentList)
{
studentInfoHolder.AppendFormat("Name: {0}\r\nSubject: {1}\r\nAge: {2}\r\nGrade: {3}",
student.Name, student.Subject, student.age, student.Grade);
}
File.WriteAllText(SaveFileDia.FileName, studentInfoHolder.ToString());
Try something more like the following. It avoids opening the file twice, and string concatenation, which is not a great idea with immutable strings.
// This line over-writes the file if it exists, or otherwise creates it.
using (TextWriter fileWriter = new StreamWriter(SaveFileDia.FileName, append: false))
{
foreach (Stud student in StudentList)
{
fileWriter.WriteLine($"Name: {student.Name}");
fileWriter.WriteLine($"Subject: {student.Subject}");
fileWriter.WriteLine($"Age: {student.age}");
fileWriter.WriteLine($"Grade: {student.Grade}");
fileWriter.WriteLine();
}
}
There's no good reason to buffer all that in memory before writing it to the file. It's easier to open the file by calling File.CreateText, and then write each line to it, like this:
private void saveTSMI_Click(object sender, EventArgs e)
{
if (lstStudNames.Items.Count == 0)
{
MessageBox.Show("Nothing to save");
return;
}
SaveFileDia.Filter = "Text Files | *.txt";
if (SaveFileDia.ShowDialog() != DialogResult.OK)
{
return;
}
// Create the file (overwrite if it already exists),
// and write each student record.
using (var outFile = File.CreateText(SaveFileDia.FileName))
{
foreach (Stud student in StudentList)
{
outFile.WriteLine("Name: " + student.Name);
outFile.WriteLine("Subject: " + student.Subject);
outFile.WriteLine("Age: " + student.age);
outFile.WriteLine("Grade: " + student.Grade);
}
}
}
I also refactored your code a bit, reversing the logic on those two tests up front so as to reduce the nesting in your code.
Update after comment
If you really want a string to contain all that stuff, then you can modify the above to do it pretty easily. Replace the loop that writes to file with this one that uses a StringWriter:
// Create a StringWriter to hold the data, and write each line.
using (var sWriter = new StringWriter())
{
foreach (Stud student in StudentList)
{
sWriter.WriteLine("Name: " + student.Name);
sWriter.WriteLine("Subject: " + student.Subject);
sWriter.WriteLine("Age: " + student.age);
sWriter.WriteLine("Grade: " + student.Grade);
}
// write the data to the file
StudentInfoHolder = sWriter.ToString();
File.WriteAllText(SaveFileDia.FileName, StudentInfoHolder);
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I am trying to to write data to a log file but nothing gets written to the file.
Aim of the program is to run a continuous loop and keep looking for file, if file is valid, process it and move it. I am logging for any errors and items that are created.
Also, how can I make my log file access able while the loop is running so that I can see that values got appended.
static void Main(string[] args)
{
var logFile = File.Create(filePath + "\\log_" + DateTime.Today.ToString("MMMM") + ".txt").ToString();
while (true)
{
try
{
var moveTo = Directory.CreateDirectory(#"" + directoryPath + "Processed_" + DateTime.Today.ToString("MMMM"));
var files = Directory.GetFiles(filePath);
var todaysDate = DateTime.Now.Date;
var firstOfMonth = new DateTime(todaysDate.Year, todaysDate.Month, 1);
var monthEnd = firstOfMonth.AddMonths(1).AddDays(-1);
if (todaysDate == monthEnd)
{
File.Move(logFile, #"" + moveToNewPath + logFile);
}
foreach (var fileName in files)
{
if (fileName.Contains("myFile.csv"))
{
var fileValues = File.ReadAllLines(filePath + fileName.Substring(44)).Skip(1).Select(v => new myFile(v)).ToList();
foreach (var i in fileValues)
{
try
{
var jsonValues = ValueFromFile(i);
var response = UploadData(url, username, password, values);
this should be written to a log file ===> .File.AppendAllText(logFile, Environment.NewLine + DateTime.Now + "\t" + response);
}
catch (Exception exception)
{
File.AppendAllText(logFile, Environment.NewLine + DateTime.Now + "\t" + exception.Message.Replace("\n", " "));
}
}
File.Move(fileName, #"" + directoryPath + "\\" + moveTo + "\\" + "processedMyFile" + DateTime.Now.Date.ToString("MM-dd-yy") + ".csv");
}
}
}
catch (Exception exception)
{
File.AppendAllText(logFile, Environment.NewLine + DateTime.Now + "\t" + exception.Message.Replace("\n", " "));
}
}
}
Let's start with this line at the top of the program:
var logFile = File.Create(filePath + "\\log_" + DateTime.Today.ToString("MMMM") + ".txt").ToString();
I'm not sure what you're doing with that ToString() call hanging off the end. It almost certainly doesn't do what you think it does. But I really want to take a closer look at the documentation for the File.Create() method here. Specifically, this excerpt:
The FileStream object created by this method has a default FileShare value of None; no other process or code can access the created file until the original file handle is closed.
Uh oh. That means the File.AppendAllText() call later on will be out of luck. But let's look at the AppendAllText() documentation. Specifically this:
The method creates the file if it doesn’t exist
Meaning you can just remove the problem line at the top. You neither need nor want it. Or maybe you just want to create the file name there, like this:
var logFile = Path.Combine(filePath, "log_" + DateTime.Today.ToString("MMMM") + ".txt");
As a bonus, I'd explore changing this code to use System.Diagnostics.Trace in conjunction with FileTraceListener and maybe a ConsoleTraceListener attached.
static string moveToNewPath = "...";
static string filePath = "...";
static string logFormat = "\n{0:s}\t{1}";
static string logFile = "";
static string directoryPath = "...";
static void LogMessage(string FilePath, string Message)
{
File.AppendAllText(Path.Combine(filePath, logFile),
string.Format(logFormat, DateTime.Now, Message.Replace("\n", " ")));
}
static void Main(string[] args)
{
logFile = "log_" + DateTime.Today.ToString("MMMM") + ".txt";
//Rotate log file on last day of month
try
{
var todaysDate = DateTime.Now.Date;
var firstOfMonth = new DateTime(todaysDate.Year, todaysDate.Month, 1);
var monthEnd = firstOfMonth.AddMonths(1).AddDays(-1);
if (todaysDate == monthEnd)
{
File.Move(Path.Combe(filePath, logFile), Path.Combine(moveToNewPath, logFile));
}
}
catch (Exception ex)
{
LogMessage(ex.Message);
}
while (true)
{
// !!!!!!!!!!!!!!
//Log rotate code used to be here... but... you need something to be sure this only happens once per day.
// I STRONGLY suspect this code should be setup to run as
// a SCHEDULED TASK set to run once per day or maybe once per hour, rather than an always-on background program.
// !!!!!!!!!!!!!!!!
try
{
var moveTo = Path.Combine(directoryPath, "Processed_" + DateTime.Today.ToString("MMMM"));
Directory.CreateDirectory(moveTo);
var files = Directory.GetFiles(filePath).Where(f => f.EndsWith("myFile.csv"));
foreach (var fileName in files)
{
var fileValues = File.ReadAllLines(filePath + fileName.Substring(44)).Skip(1).Select(v => new myFile(v));
foreach (var i in fileValues)
{
try
{
var jsonValues = ValueFromFile(i);
var response = UploadData(url, username, password, jsonValues);
LogMessage(response);
}
catch (Exception ex)
{
LogMessage(ex.Message);
}
}
File.Move(fileName, Path.Combine(moveTo, "processedMyFile" + DateTime.Now.Date.ToString("MM-dd-yy") + ".csv"));
}
}
catch (Exception ex)
{
LogMessage(ex.Message);
}
}
}
I have this function to delete files older than X amount of months, but it doesn't seem to delete them when I run the code: any guesses to why? When I check folder they are still there.
public static void deleteFiles()
{
try
{
DirectoryInfo ddi = new DirectoryInfo(destination_path);
if (ddi.Exists)
{
logFile.WriteLine("Log Entry: {0}", String.Format("{0:f}", dt) + System.Environment.NewLine);
foreach (var filename in ddi.EnumerateFiles())
{
FileInfo fi = new FileInfo(filename.ToString());//(destination_path + "\\" + filename);
if (fi.CreationTime < dt.AddMonths(-1) )
{
try
{
fi.Delete();
logFile.WriteLine("{0} was deleted successfully.", destination_path + "\\" + filename);
}
catch (Exception ex)
{
logFile.WriteLine("The deletion process failed: {0}", ex.Message);
}
}
}
logFile.WriteLine(String.Concat(Enumerable.Repeat("-------", 25)));
logFile.WriteLine();
}
}
catch (DirectoryNotFoundException ex)
{
logFile.WriteLine("Log Entry: {0}", String.Format("{0:f}", dt) + System.Environment.NewLine);
logFile.WriteLine("Could not delete files from specified directory: {0}", ex.Message);
logFile.WriteLine(String.Concat(Enumerable.Repeat("-------", 25)));
logFile.WriteLine();
}
}
As "Alessandro D'Andria" points out the documentation says:
https://msdn.microsoft.com/en-us/library/system.io.fileinfo.delete(v=vs.110).aspx
"If the file does not exist, this method does nothing."
This makes you think that the file delete has worked and is masking the issue.
If you look at the line:
foreach (var filename in ddi.EnumerateFiles())
this is returning a FileInfo object which is basically a link to the file you want to delete.
But the next line, creates a new FileInfo object based on the filename.
FileInfo fi = new FileInfo(filename.ToString());
But the filename.ToString() is just returning the filename, there is no path information in here.
If you run through the debugger you will see that the fi object will have a pathname (fi.Directory) which is not your destination_path, but is in fact the path of your running executable.
Therefore, fi.Delete() does not actually find the file, so it does nothing (as per the documentation) but you still write a 'success' message to your log file and no exception is thrown, so you wrongly think that everything has worked.
So you actually want something more like this;
if (filename.CreationTime < dt.AddMonths(-1))
{
try
{
if (!filename.Exists)
throw new Exception("File does not exist");
filename.Delete();
WriteLine("{0} was deleted successfully.", destination_path + "\\" + filename);
}
catch (Exception ex)
{
WriteLine("The deletion process failed: {0}", ex.Message);
}
}
Try with the full path:
string path = Path.Combine(destination_path,filename.ToString());
FileInfo fi = new FileInfo(path);
Try something like.... (Ive left out some of your logic but the principle is the same....)
You don't need to use fileinfo as far as I can see.
{
string[] files = Directory.GetFiles(destination_path);
foreach (string filename in files)
{
if (File.Exists(destination_path + "\\" + filename))
{
try
{
File.Delete(destination_path + "\\" + filename);
}
catch (Exception ex)
{
logFile.WriteLine("The deletion process failed: {0}", ex.Message);
}
}
}
}
i know this seems pretty simple and i know theres other questions asking this but i just need to know what im personally doing wrong and why it doesnt work because it should.
int ImageCounter = 1;
foreach (var Image in ImageFilePaths)
{
{
// Console.WriteLine(Image);
// Console.WriteLine(RenameFolderPath + #"\" + ImageCounter + ".jpeg");
File.Move(Image, RenameFolderPath + #"\" + ImageCounter + ".jpeg");
ImageCounter++;
}
}
So theres about 150 images in a folder and after running this, im left with 11, 10 of which are numbered 1-10 and the 11th is left with its original name.
if i print (image) it will print about 150 of the original names, if i print the 2nd writeline, it will print the exact same but "1 - about 150" instead of the original name. so theres no problems there, it must be with the file.move but i cannot see anything wrong
Not sure what the rest of your code looks like, but this works for me:
void Main()
{
MoveFiles(#"c:\Temp\MoveTest", #"C:\Temp\MoveTest1");
}
public void MoveFiles(string fromDir, string toDir)
{
int ImageCounter = 1;
// Take a snapshot of the file system.
System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(fromDir);
IEnumerable<System.IO.FileInfo> ImageFilePaths = dir.GetFiles("*.*", System.IO.SearchOption.TopDirectoryOnly);
foreach (var Image in ImageFilePaths)
{
{
Console.WriteLine(Image);
Console.WriteLine(toDir + #"\" + ImageCounter + ".jpeg");
File.Move(Image.FullName, toDir + #"\" + ImageCounter + ".jpeg");
ImageCounter++;
}
}
}