A while back I needed to rename a bunch of pictures, prefixing them with numbers, so that they'd sort the way I wanted.

Here's the code I used. I ran this in LINQPad, but you could use it in a console app with minor modifications. One nice thing I learned to do: get image datetime without loading the whole image.

Hope this is useful to you in some way!

void Main()
{
	string path = @"C:\Users\charles\Pictures\Inbox\20160630";
	List<FileChange> list = new List<UserQuery.FileChange>();

    foreach (string fileName in Directory.GetFiles(path))
	{
		DateTime taken;
		try
		{
			taken = GetDateTakenFromImage(fileName);
		}
		catch
		{
			try
			{
				taken = GetDateTakenFromFilename(fileName);
			}
			catch
			{
				taken = File.GetLastWriteTime(fileName);
				if (File.GetCreationTime(fileName) < taken) { taken = File.GetCreationTime(fileName); }
			}
		}
		FileChange item = new FileChange(fileName, "", taken);
		//set new taken on to old.
		item.NewTakenOn = item.OldTakenOn;
		list.Add(item);
	}

	//sort and set new name
	int newNbr = 1;
	foreach (var item in list.OrderBy(l => l.OldTakenOn))
	{
		item.DestinationFileName = GetNewFileName(item.SourceFileName, newNbr);
		newNbr++;
	}
	
	DumpList(list.OrderBy(l => l.OldTakenOn).ToList());
	DumpList(list.OrderBy(l => l.NewTakenOn).ToList());
	
	//rename
	list.ForEach(a => File.Move(a.SourceFileName, a.DestinationFileName));
}

public static void DumpList(List<FileChange> list)
{
	var newList = list
	.Select(l => new { oldName = Path.GetFileName(l.SourceFileName), newName = Path.GetFileName(l.DestinationFileName), l.OldTakenOn, l.NewTakenOn });
	newList.Dump();
}

//http://stackoverflow.com/questions/180030/how-can-i-find-out-when-a-picture-was-actually-taken-in-c-sharp-running-on-vista
//we init this once so that if the function is repeatedly called
//it isn't stressing the garbage man
private static Regex r = new Regex(":");

//retrieves the datetime WITHOUT loading the whole image
public static DateTime GetDateTakenFromImage(string path)
{
	using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
	using (Image myImage = Image.FromStream(fs, false, false))
	{
		//if (!myImage.PropertyIdList.Any(a => a == 36867)){ return DateTime.Parse("1/1/1900");}
		PropertyItem propItem = myImage.GetPropertyItem(36867);
		string dateTaken = r.Replace(Encoding.UTF8.GetString(propItem.Value), "-", 2);
		//string t = Encoding.UTF8.GetString(propItem.Value);
		return DateTime.Parse(dateTaken);
	}
}

public static DateTime GetDateTakenFromFilename(string path)
{
	var takenPartSplit = path.Substring(3, 15).Split('_');
	string datePart = takenPartSplit[0];
	string timePart = takenPartSplit[1];
	datePart = datePart.Substring(0, 4) + "-" + datePart.Substring(4, 2) + "-" + datePart.Substring(6, 2);
	timePart = timePart.Substring(0, 2) + ":" + timePart.Substring(2, 2) + ":" + timePart.Substring(4, 2);
	string datetime = datePart + " " + timePart;
	return DateTime.Parse(datetime);
}

public static string GetNewFileName(string path, int newNumber)
{
	string oldName = Path.GetFileName(path);
	string newName = oldName;
	newName = newNumber.ToString().PadLeft(3, '0') + " " + newName;
	return path.Replace(oldName, newName);
}

public class FileChange
{
	public string SourceFileName { get; set; }
	public string DestinationFileName { get; set; }
	public DateTime OldTakenOn { get; set; }
	public DateTime NewTakenOn { get; set; }

	public FileChange(string source, string destination, DateTime takenOn)
	{
		SourceFileName = source;
		DestinationFileName = destination;
		OldTakenOn = takenOn;
	}
}