一次性取决于其他一次性用品

时间:2018-01-11 19:15:49

标签: c# .net

我有一个应用程序,它根据字符串列表处理文件流,字符串可以是磁盘上的文件,也可以是Zip文件中的文件。要清理代码,我想重构打开文件的过程。

我已经创建了一个返回文件内容Stream的方法,但是因为流依赖于ZipFile IDisposable,所以当我读取流时,ZipFile会被抛出异常。

void Main()
{
    using (var stream = OpenFileForImport("zipfile.zip;insidefile.txt"))
        new StreamReader(stream).ReadToEnd(); // Exception

    using (var stream = OpenFileForImport("outside.txt"))
        new StreamReader(stream).ReadToEnd(); // Works
}
public static Stream OpenFileForImport(string filePath)
{
    var path = Path.Combine(basefolder, filePath);

    if (path.Contains(";"))
    {
        var parts = path.Split(';');
        var zipPath = parts[0];

        //Error checking logic to ensure zip file exists and is valid...
        using (var zip = ZipFile.OpenRead(zipPath))
        using (var entry = zip.GetEntry(parts[1]))
        {
            //Error checking logic to ensure inside file exists within zip file.
            return entry.Open();
        }

    }

    var file = new FileInfo(path);
    if (file != null)
        return file.OpenRead();

    return null;

}

我可以从zipentry声明中删除using子句,但我怀疑它们是否会被处理掉。当它取决于其他一次性用品时,是否有合适的模式来退回一次性用品?

2 个答案:

答案 0 :(得分:2)

不要直接返回流,而是返回一个一次性对象,该对象可以提供您想要处理的流,但是当它被处置时清除该流和其他相关资源的:

public class NameToBeDetermined : IDisposable
{
    private ZipFile zip;
    public Stream Stream { get; }
    public NameToBeDetermined(ZipFile zip, Stream stream)
    {
        this.zip = zip;
        Stream = stream;
    }
    public void Dispose()
    {
        zip.Dispose();
        Stream.Dispose();
    }
}

然后返回那个,而不是流本身。如果值得花时间,你可以将该包装器转换为Stream本身,只将所有Stream方法转发到合成流中,但这样做会在处理时完成额外的工作。是否值得花时间创建更具参与性的包装而不是让调用者访问Stream属性取决于您。

答案 1 :(得分:1)

您可能应该将文件从ZipEntry复制到MemoryStream,以便您可以使用副本。

    //Error checking logic to ensure zip file exists and is valid...
    using (var zip = ZipFile.OpenRead(zipPath))
    using (var entry = zip.GetEntry(parts[1]))
    {
        //Error checking logic to ensure inside file exists within zip file.
        MemoryStream stream = new MemoryStream();
        entry.Open().CopyTo(stream);
        stream.Seek(0, SeekOrigin.Begin); 
        return stream;
    }