【发布时间】:2013-02-05 10:53:25
【问题描述】:
我试图了解 .NET 4.5 中的变化,主要是异步功能。为了解决这个问题,我想我会创建一个小应用程序来归档我的大量照片集。这样做我学得最好,该应用程序有双重目的。
我已经阅读了很多关于使用异步的 MSDN 文章,但我认为我对它的理解不够好(因为它不起作用)。我的意图是将源文件夹中的每张照片根据拍摄日期复制到目标文件夹(或者如果拍摄的元数据丢失则创建)。同时将其重命名为标准命名约定,并在图像框中存档图像时显示图像。我希望应用程序在工作期间保持响应,这就是异步的用武之地。现在应用程序的目的并不重要,重点是让我了解异步。
实际发生的情况是应用程序无响应,按预期归档所有图像,但图像框仅显示最终图片。异步开始文件传输然后继续下一个图像,开始传输然后继续等等等等,所以我最终得到了数百个打开的文件流,而不是等待每个文件关闭。
任何我出错的地方都将不胜感激。我对使用任务的理解是不稳定的,返回一个任务有什么用?
imgMain 是 XAML 文件中的图像框。 async/await 在存档方法中,但显示所有可能相关的代码。
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);
}
}
}
}
}
【问题讨论】:
-
我不是 .Net 4.5 的新异步/等待功能方面的专家,但对我来说确实很突出的一件事是,您唯一异步运行的是文件副本。我相信你会得到一些有用的答案,尽管有更好的指导。
-
@DanielKelley 您还想异步运行什么?
-
@svick 根据您的回答-存档中的所有内容。除了
awaitingfs.CopyToAsync之外,其他一切都在占用 UI 线程。 -
@DanielKelley 它仍然是,即使你
await是Archive()的结果。但是: 1. 应该没问题,里面看不到长的操作。 2. 这些操作没有异步版本。 -
@svick 也许我的评论措辞不当——我并不是说每个操作都应该使用异步方法执行(例如文件删除)。我的意思是他正在等待文件副本,而不是他对
Archive的调用——由于方法的签名不正确,他不能这样做。
标签: c# .net asynchronous .net-4.5 async-await