1

我正在尝试使用 C# 在 Windows 应用商店中制作 epub 解析应用程序,它不会等待存档(epub 实际上是 zip 文件)在尝试解析尚不存在的目录之前完成提取. 如何让我的应用更有耐心?

我试过让我的 UnZip() 函数返回一个任务并让 epub 构造函数(epub 是一个类)使用 UnZip().Wait(),但这只会冻结应用程序。我该怎么办?

编辑:这是我的相关代码:

public class epub
{
    public string filename;
    private StorageFolder unzipFolder;
    private IList<epubChapter> _contents;
    private bool _parsed = false;
    public bool parsed { get { return _parsed; } } //Epub and contents are fully parsed

    public epub(string newFilename)
    {
        _contents = new List<epubChapter>();
        filename = newFilename;
        UnZipFile().Wait();
        getTableOfContents();
    }

    private async Task UnZipFile()
    {
        var sourceFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
        StorageFolder localFolder = ApplicationData.Current.LocalFolder;

        unzipFolder = await localFolder.CreateFolderAsync(filename, CreationCollisionOption.OpenIfExists);

        using (var zipStream = await sourceFolder.OpenStreamForReadAsync(filename))
        {
            using (MemoryStream zipMemoryStream = new MemoryStream((int)zipStream.Length))
            {
                await zipStream.CopyToAsync(zipMemoryStream);

                using (var archive = new ZipArchive(zipMemoryStream, ZipArchiveMode.Read))
                {
                    foreach (ZipArchiveEntry entry in archive.Entries)
                    {
                        if (entry.Name != "")
                        {
                            using (Stream fileData = entry.Open())
                            {
                                try
                                {
                                    await unzipFolder.GetFileAsync(entry.Name);
                                    Debug.WriteLine("File at {0} already exists", entry.Name);
                                    continue;
                                }
                                catch (FileNotFoundException)
                                {
                                    Debug.WriteLine("Creating file {0}", entry.Name);
                                }

                                StorageFile outputFile = await unzipFolder.CreateFileAsync(entry.Name, CreationCollisionOption.OpenIfExists);

                                //Debug.WriteLine("Output file created at {0}", outputFile.Path);
                                using (Stream outputFileStream = await outputFile.OpenStreamForWriteAsync())
                                {
                                    await fileData.CopyToAsync(outputFileStream);
                                    await outputFileStream.FlushAsync();
                                }
                            }

                            if (entry.Name == "toc.ncx")
                            {
                                Debug.WriteLine("toc.ncx found in epub file; parsing it");
                                getTableOfContents();
                            }
                        }
                    }
                }
            }
        }
    }

    public void getTableOfContents()
    {
        string contentsPath = unzipFolder.Path + @"\toc.ncx"; //The file is always called this in valid epubs

        try
        {
            XDocument toc = XDocument.Load(contentsPath);
            string nameSpace = getNameSpace(toc);
            XElement navMap = firstElementNamed(toc.Root, "navMap");
            parseNavPoints(navMap, nameSpace, 0);
            _parsed = true;
        }
        catch(FileNotFoundException)
        {
            Debug.WriteLine("File toc.ncx was not found!");
        }

    }
4

1 回答 1

2

基本上,您的问题似乎是:如何async从构造函数中调用方法?

简短的回答是你没有,而是async为你的类创建一个工厂方法。

更长的答案:正如您所注意到的,如果您调用Wait(),您的代码将阻塞。你不能使用await,因为构造函数不能async。如果你什么都不做,构造函数会过早返回。

这里的解决方案是使用async工厂方法而不是构造函数。就像是:

private epub(string newFilename)
{
    _contents = new List<epubChapter>();
    filename = newFilename;
}

public static async Task<epub> CreateAsync(string newFilename)
{
    var result = new epub(newFilename);
    await result.UnZipFile();
    result.getTableOfContents();
    return result;
}

有关更多信息和替代解决方案,请参阅Stephen Cleary 的关于async和 contructors的文章。

于 2013-06-11T16:37:56.973 回答