Когда на жестком диске лежит около 10 ГБ отснятых разными аппаратами цифровых фотографий, разложить все это по полочкам не так уж просто.
Конечно, наверняка существуют платные и бесплатные приложения, помогающие разложить фотографии по папкам на основании данных о дате съемки, но для моих требований оказалось проще написать небольшую консольную программу на C#, почти скрипт.
Исходил из следующего:
1. Все фотографии разложены в папки по годам и месяцам (попытки навести порядок предпринимались неоднократно). Необходимо чтобы структура папок была сохранена.
2. Фотографии в папках некорректно отсортированы, т.к. снимал двумя телефонами и двумя фотоаппаратами, у каждого свой формат именования файла. Необходимо переименовать файлы так, чтобы сортировка по имени была сразу же сортировкой по дате, камере. Для надежности, сохранить старое имя файла.
Таким образом, нужно чтобы, файл, например, D:\Pictures\2008-03\11032008.jpg был скопирован в D:\Pictures New\2008-03\20080311 08.26.37 Nokia 5800 Xpres 11032008.jpg
А старую папку пожму архиватором в архив.
Оказалось, что в .NET 3.5 есть удобные классы для чтения метаданных из файла.
В итоге, за небольшое время получается такой код:
Конечно, наверняка существуют платные и бесплатные приложения, помогающие разложить фотографии по папкам на основании данных о дате съемки, но для моих требований оказалось проще написать небольшую консольную программу на C#, почти скрипт.
Исходил из следующего:
1. Все фотографии разложены в папки по годам и месяцам (попытки навести порядок предпринимались неоднократно). Необходимо чтобы структура папок была сохранена.
2. Фотографии в папках некорректно отсортированы, т.к. снимал двумя телефонами и двумя фотоаппаратами, у каждого свой формат именования файла. Необходимо переименовать файлы так, чтобы сортировка по имени была сразу же сортировкой по дате, камере. Для надежности, сохранить старое имя файла.
Таким образом, нужно чтобы, файл, например, D:\Pictures\2008-03\11032008.jpg был скопирован в D:\Pictures New\2008-03\20080311 08.26.37 Nokia 5800 Xpres 11032008.jpg
А старую папку пожму архиватором в архив.
Оказалось, что в .NET 3.5 есть удобные классы для чтения метаданных из файла.
В итоге, за небольшое время получается такой код:
using System;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using System.Windows.Media.Imaging;
namespace Exifer
{
class Program
{
static void Main(string[] args)
{
var sourceDirectoryPath = string.Empty;
var targetDirectoryPath = string.Empty;
var mask = string.Empty;
if (args.Length == 3)
{
sourceDirectoryPath = args[0];
targetDirectoryPath = args[1];
mask = args[2];
}
while (!Directory.Exists(sourceDirectoryPath))
{
Console.WriteLine("Source path:");
sourceDirectoryPath = Console.ReadLine();
}
while (!Directory.Exists(targetDirectoryPath))
{
Console.WriteLine("Target path:");
targetDirectoryPath = Console.ReadLine();
if (!string.IsNullOrEmpty(targetDirectoryPath))
Directory.CreateDirectory(targetDirectoryPath);
}
while (string.IsNullOrEmpty(mask))
{
Console.WriteLine("Mask:");
mask = Console.ReadLine();
}
var pathes = GetFilesRecursive(sourceDirectoryPath, mask);
foreach (var oldFilePath in pathes)
{
var fileStream = new FileStream(
oldFilePath, // path
FileMode.Open, // mode
FileAccess.Read, // access
FileShare.Read); // share
var jpegBitmapDecoder = new JpegBitmapDecoder(
fileStream, // bitmapStream
BitmapCreateOptions.PreservePixelFormat, // createOptions
BitmapCacheOption.Default); // casheOption
var bitmapFrame = jpegBitmapDecoder.Frames.FirstOrDefault();
var newFilePath = string.Empty;
if (bitmapFrame != null)
{
var bitmapMetadata = jpegBitmapDecoder.Frames[0].Metadata as BitmapMetadata;
if (bitmapMetadata != null)
{
if (!string.IsNullOrEmpty(bitmapMetadata.DateTaken))
newFilePath += Convert.ToDateTime(bitmapMetadata.DateTaken)
.ToString("yyyyMMdd HH.mm.ss");
if (!string.IsNullOrEmpty(bitmapMetadata.CameraManufacturer))
newFilePath += " " + bitmapMetadata.CameraManufacturer;
if (!string.IsNullOrEmpty(bitmapMetadata.CameraModel))
newFilePath += " " + bitmapMetadata.CameraModel;
}
newFilePath += " " + Path.GetFileNameWithoutExtension(oldFilePath);
}
newFilePath = oldFilePath
.Replace(sourceDirectoryPath, targetDirectoryPath)
.Replace(Path.GetFileName(oldFilePath), newFilePath + Path.GetExtension(oldFilePath));
if (!Directory.Exists(newFilePath))
Directory.CreateDirectory(Path.GetDirectoryName(newFilePath));
File.Copy(
oldFilePath, // sourceFileName
newFilePath, // destFileName
false); // overwrite
Console.WriteLine("{0} -> {1}", Path.GetFileName(oldFilePath), Path.GetFileName(newFilePath));
}
Console.ReadKey();
}
public static List<string> GetFilesRecursive(string path, string searchPattern)
{
var result = new List<string>();
var stack = new Stack<string>();
stack.Push(path);
while (stack.Count > 0)
{
var directory = stack.Pop();
result.AddRange(Directory.GetFiles(directory, searchPattern));
foreach (var subdirectory in Directory.GetDirectories(directory)) stack.Push(subdirectory);
}
return result;
}
}
}
* This source code was highlighted with Source Code Highlighter.
Все 10 гигов обработало успешно.
Правда, в них были только файлы с расширением *.jpg, на других не проверял.