私は.NET4.5の変更点、主に非同期機能に頭を悩ませようとしています。頭を悩ませるために、膨大な写真コレクションをアーカイブするための小さなアプリを作成しようと思いました。私はそうすることで最もよく学びます。そうすることで、アプリケーションは2つの目的を果たします。
非同期の使用に関するMSDNの記事をたくさん読んだことがありますが、(機能していないため)非同期について十分に理解していないと思います。私の意図は、撮影日(または撮影したメタデータがない場合は作成)に基づいて、ソースフォルダーの各写真を宛先フォルダーにコピーすることでした。同時に、名前を標準の命名規則に変更し、画像ボックスにアーカイブされた画像を表示します。非同期が発生する作業中もアプリケーションが応答し続けるようにしたかったのです。アプリの目的は重要ではなくなったので、全体のポイントは非同期に頭を悩ませることでした。
実際に発生するのは、アプリが応答しなくなり、意図したとおりにすべての画像をアーカイブしますが、画像ボックスには最終的な画像のみが表示されます。Asyncはファイル転送を開始してから次の画像に移動し、転送を開始してから次に進むなどのように、それぞれが閉じるのを待つのではなく、何百もの開いているファイルストリームになってしまいます。
私が間違っているところのポインタをいただければ幸いです。タスクの使用についての私の理解は不安定ですが、タスクを返すことはどのような目的に役立ちますか?
imgMainは、XAMLファイルのイメージボックスです。async / awaitはarchiveメソッドにありますが、関連する可能性があるため、すべてのコードが表示されます。
using System;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Forms;
using System.IO;
namespace PhotoArchive
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private string Source
{
get { return txtSource.Text; }
set { txtSource.Text = value; }
}
private string Destination
{
get { return txtDestination.Text; }
set { txtDestination.Text = value; }
}
public MainWindow()
{
InitializeComponent();
}
private void btnBrowseDataSource_Click(object sender, RoutedEventArgs e)
{
var dialogue = new FolderBrowserDialog();
dialogue.ShowDialog();
Source = dialogue.SelectedPath;
}
private void btnBrowseDestination_Click(object sender, RoutedEventArgs e)
{
var dialogue = new FolderBrowserDialog();
dialogue.ShowDialog();
Destination= dialogue.SelectedPath;
}
private void btnSort_Click(object sender, RoutedEventArgs e)
{
var files = Directory.GetFiles(Source, "*.*", SearchOption.AllDirectories);
var result = from i in files
where i.ToLower().Contains(".jpg") || i.ToLower().Contains(".jpeg") || i.ToLower().Contains(".png")
select i;
foreach (string f in result)
{
DateTime dest = GetDateTakenFromImage(f);
Archive(f, Destination, dest);
}
}
private async void Archive(string file, string destination, DateTime taken)
{
//Find Destination Path
var sb = new StringBuilder();
sb.Append(destination);
sb.Append("\\");
sb.Append(taken.ToString("yyyy"));
sb.Append("\\");
sb.Append(taken.ToString("MM"));
sb.Append("\\");
if (! Directory.Exists(sb.ToString()))
{
Directory.CreateDirectory(sb.ToString());
}
sb.Append(taken.ToString("dd_MM_yyyy_H_mm_ss_"));
sb.Append((Directory.GetFiles(destination, "*.*", SearchOption.AllDirectories).Count()));
string[] extension = file.Split('.');
sb.Append("." + extension[extension.Length-1]);
using (FileStream fs = File.Open(file, FileMode.Open))
using (FileStream ds = File.Create(sb.ToString()))
{
await fs.CopyToAsync(ds);
fs.Close();
File.Delete(file);
}
ImgMain.Source = new BitmapImage(new Uri(sb.ToString()));
}
//get date info
private static Regex r = new Regex(":");
public static DateTime GetDateTakenFromImage(string path)
{
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
using (System.Drawing.Image img = System.Drawing.Image.FromStream(fs, false, false))
{
PropertyItem prop;
try
{
prop = img.GetPropertyItem(36867);
}
catch (Exception)
{
prop = img.GetPropertyItem(306);
}
string dateTaken = r.Replace(Encoding.UTF8.GetString(prop.Value), "-", 2);
return DateTime.Parse(dateTaken);
}
}
}
}
}