ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

C#异步文件传输 – 在继续循环之前等待

2019-05-17 18:56:36  阅读:187  来源: 互联网

标签:c asynchronous net async-await net-4-5


我试图了解.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);
            }
        }


    }
}

}

解决方法:

My understanding of using Tasks is shakey, returning a task serves what purpose?

Task是异步操作的表示.任务完成后,表示操作已完成.您可以等待任务,这意味着您将异步等待它完成(不阻止UI线程).

但是如果你使方法异步无效,则无法等待操作完成.当方法返回时,您知道异步操作已经启动,但就是这样.

您需要做的是更改Archive()以返回Task,以便您可以等待它在事件处理程序中完成.任务将自动返回,您不需要(或可以)添加任何返回.

因此,将Archive()的签名更改为:

private async Task Archive(string file, string destination, DateTime taken)

然后在您的事件处理程序(您还需要更改为异步)中等待它:

private async void btnSort_Click(object sender, RoutedEventArgs e)
{
    // snip

    foreach (string f in result)
    {
        DateTime dest = GetDateTakenFromImage(f);
        await Archive(f, Destination, dest);
    }
}

通常,async void方法只应用于事件处理程序.所有其他异步方法应该是异步任务(或异步任务< SomeType>如果它们返回一些值),以便您可以等待它们.

标签:c,asynchronous,net,async-await,net-4-5
来源: https://codeday.me/bug/20190517/1123205.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有