异步FileIO方法混合WinRT应用程序中的图像

时间:2014-09-14 20:37:55

标签: c# asynchronous windows-runtime winrt-async

所以我在我的应用程序中实现了一个方法,从一个站点下载给定漫画的图像,并将所述图像放入应用程序的AppData(localstate)文件夹中language文件夹内title }文件夹。

图像下载工作完美,除了我尝试一次下载多个图像集之外,结果在所涉及的文件夹中混合。

处理文件IO的方法:

private async Task<bool> SaveManga(Data.Posts.Content2 manga)
    {
        var folder = ApplicationData.Current.LocalFolder;
        var safeName = Path.GetInvalidFileNameChars().Aggregate(manga.ContentInfo.ContentName, (current, c) => current.Replace(c, '_').Replace('.', '_'));

        // Create folder for issue if does not exist
        var issueFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync(safeName, CreationCollisionOption.OpenIfExists);
        // Create folder for language if does not exist
        var langFolder = await issueFolder.CreateFolderAsync(manga.ContentInfo.ContentLanguage, CreationCollisionOption.OpenIfExists);

        // Populate pages if page count is 0
        if (manga.Pages == null)
            manga.Pages = new Dictionary<int, Data.Posts.Page>();
        if (manga.Pages.Count == 0)
        {
            if (NetworkInterface.GetIsNetworkAvailable() == false)
            {

            }
            var pages = Fakku.GetMangaInfo(manga.ContentInfo.ContentUrl).Result.Pages;
            for (var i = 0; i < pages.Count; i++)
            {
                var page = new Data.Posts.Page { Image = pages.Values.ElementAt(i).Image, Thumb = pages.Values.ElementAt(i).Thumb };
                manga.Pages.Add(i, page);
            }
        }
        var files = await langFolder.GetItemsAsync();
        var fileCount = files.Count;
        if (fileCount + 3 == manga.ContentInfo.ContentPages) return true;
        var cbi = new BitmapImage(new Uri(manga.ContentInfo.ContentImages.Cover));
        const string cname = "cover.jpg";
        var wcbi = await WriteableBitmapFromBitmapImageExtension.FromBitmapImage(cbi);
        await wcbi.SaveToFile(langFolder, cname, CreationCollisionOption.OpenIfExists);


        var sbi = new BitmapImage(new Uri(manga.ContentInfo.ContentImages.Sample));
        const string sname = "sample.jpg";
        var wsbi = await WriteableBitmapFromBitmapImageExtension.FromBitmapImage(sbi);
        await wsbi.SaveToFile(langFolder, sname, CreationCollisionOption.OpenIfExists);

        for (var i = 1; i < manga.ContentInfo.ContentPages; i++)
        {
            var bi = new BitmapImage(new Uri(manga.Pages[i].Image));
            //var x = await langFolder.CreateFileAsync(String.Format("{0}.png", i), CreationCollisionOption.ReplaceExisting);
            var imgName = String.Format("{0}.jpg", i);
            try
            {
                var wbi = await WriteableBitmapFromBitmapImageExtension.FromBitmapImage(bi);
                await wbi.SaveToFile(langFolder, imgName, CreationCollisionOption.OpenIfExists);
            }
            catch (Exception e)
            {
                var hResult = (uint)e.HResult;
                if (hResult.Equals(0x80190194))
                {
                    new MessageDialog("Error loading pages. \n  If this is a sample manga, this behavior is to be expected.").ShowAsync();
                    break;
                }
            }
        }
        return true;
    }

实施:

private async void SaveButton_Click(object sender, RoutedEventArgs e)
    {
        SaveButton.IsEnabled = false;
        if (isSaved)
        {
            var i = defaultViewModel.ContentInfo;
            Fakku.SavedManga.RemoveAll(x => x.ContentInfo.ContentUrl == i.ContentUrl);
            isSaved = !isSaved;
            SaveButton.Content = "Save";
            var manga = defaultViewModel;
            await RemoveManga(manga);
            await ProcessSaved();
            SaveButton.IsEnabled = true;
        }
        else if (!isSaved)
        {
            Fakku.SavedManga.Add(defaultViewModel);
            isSaved = true;
            SaveButton.Content = "Remove";
            try
            {
                var manga = defaultViewModel;
                //pendingWork = SaveManga(manga);

                _saves.Enqueue(manga);
                await AsyncParallelForEach(
_saves, async save => await SaveManga(manga), 8,
TaskScheduler.FromCurrentSynchronizationContext());
                //HandleSaving();
                await ProcessSaved();
            }
            catch (NullReferenceException)
            {

            }
            SaveButton.IsEnabled = true;
        }
    }

AsParallel函数:

private static Task AsyncParallelForEach<T>(
IEnumerable<T> source, Func<T, Task> body,
int maxDegreeOfParallelism = DataflowBlockOptions.Unbounded,
TaskScheduler scheduler = null)
    {
        var options = new ExecutionDataflowBlockOptions
        {
            MaxDegreeOfParallelism = maxDegreeOfParallelism
        };
        if (scheduler != null)
            options.TaskScheduler = scheduler;

        var block = new ActionBlock<T>(body, options);

        foreach (var item in source)
            block.Post(item);

        block.Complete();
        return block.Completion;
    }

平行foreach的使用是我最近的尝试,取自this文章,但结果模仿我上面描述的内容,我觉得我仍然缺少一些非常重要的东西。

有人能指出我正确的方向吗?我正试图找到一种方法来处理这些下载,即同时处理SaveManga方法的多个实例,或者至少将它们排队等待完成。

编辑:我开始意识到我需要关注的是并行化,而不是异步性,如果我想同时运行下载,这是我更喜欢的。

1 个答案:

答案 0 :(得分:0)

我认为问题在于您正在并行化初始化(文件夹创建+页数),然后它会混淆每一个。

我建议先进行初始化:

public async Task InitAsync(Data.Posts.Content2 manga){
    var folder = ApplicationData.Current.LocalFolder;
        var safeName = Path.GetInvalidFileNameChars().Aggregate(manga.ContentInfo.ContentName, (current, c) => current.Replace(c, '_').Replace('.', '_'));

        // Create folder for issue if does not exist
        var issueFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync(safeName, CreationCollisionOption.OpenIfExists);
        // Create folder for language if does not exist
        var langFolder = await issueFolder.CreateFolderAsync(manga.ContentInfo.ContentLanguage, CreationCollisionOption.OpenIfExists);

        // Populate pages if page count is 0
        if (manga.Pages == null)
            manga.Pages = new Dictionary<int, Data.Posts.Page>();
        if (manga.Pages.Count == 0)
        {

            var pages = Fakku.GetMangaInfo(manga.ContentInfo.ContentUrl).Result.Pages;
            for (var i = 0; i < pages.Count; i++)
            {
                var page = new Data.Posts.Page { Image = pages.Values.ElementAt(i).Image, Thumb = pages.Values.ElementAt(i).Thumb };
                manga.Pages.Add(i, page);
            }
        }

        var cbi = new BitmapImage(new Uri(manga.ContentInfo.ContentImages.Cover));
        const string cname = "cover.jpg";
        var wcbi = await WriteableBitmapFromBitmapImageExtension.FromBitmapImage(cbi);
        await wcbi.SaveToFile(langFolder, cname, CreationCollisionOption.OpenIfExists);


        var sbi = new BitmapImage(new Uri(manga.ContentInfo.ContentImages.Sample));
        const string sname = "sample.jpg";
        var wsbi = await WriteableBitmapFromBitmapImageExtension.FromBitmapImage(sbi);
        await wsbi.SaveToFile(langFolder, sname, CreationCollisionOption.OpenIfExists);
}

然后只做这样的一些并行化,因为框架将足够智能来管理线程:):

  List<Task> tasksToWait = new List<Task>();
for (var i = 1; i < manga.ContentInfo.ContentPages; i++)
        {
taskToWait.Add(Task.Run(()=>SaveMangaPage(i));
}
await Task.WhenAll(tasksToWait );
await ProcessSaved();

使用SaveMangaPage:

public async Task SaveMangaPage(int pageNumber) {

 var bi = new BitmapImage(new Uri(manga.Pages[pageNumber].Image));
 //var x = await langFolder.CreateFileAsync(String.Format("{0}.png", pageNumber), CreationCollisionOption.ReplaceExisting);
 var imgName = String.Format("{0}.jpg", pageNumber);
 try
   {
  var wbi = await WriteableBitmapFromBitmapImageExtension.FromBitmapImage(bi);
  await wbi.SaveToFile(langFolder, imgName, CreationCollisionOption.OpenIfExists);
 }
 catch (Exception e)
  {
     var hResult = (uint)e.HResult;
     if (hResult.Equals(0x80190194))
     {
                    new MessageDialog("Error loading pages. \n  If this is a sample manga, this behavior is to be expected.").ShowAsync();
                    break;
      }
 }
}
}