C#将归档文件合并为一个文件

问题描述

代码

public void mergeFiles(string dir)
{
    for (int i = 0; i < parts; i++)
    {
        if (!File.Exists(dir))
        {
            File.Create(dir).Close();
        }
        var output = File.Open(dir,FileMode.Open);
        var input = File.Open(dir + ".part" + (i + 1),FileMode.Open);
        input.copyTo(output);
        output.Close();
        input.Close();
        File.Delete(dir + ".part" + (i + 1));
    }
}

dir变量例如是/path/file.txt.gz

我有一个文件打包到.gz存档中。该档案库分为例如我想得到8个部分。

问题是我不知道如何组合这些文件“ file.gz.part1 ...”以在以后提取它们。

使用上述功能时,存档已损坏。
我在互联网上苦苦挣扎了一个星期,但这是我找到的最好的解决方案,它不起作用。

有人对如何将存档部分合并到一个文件中有任何建议吗?

解决方法

您的代码有一些问题。如果您查看the documentation for System.IO.Stream.Close,将会看到以下备注(强调我的意思):

关闭当前流并释放与当前流关联的所有资源(例如套接字和文件句柄)。 请确保已正确处理流,而不是调用此方法。

因此,根据文档,您希望处理流而不是直接调用close(稍后再讲)。忽略这一点,您的主要问题就在这里:

var output = File.Open(dir,FileMode.Open);

您正在使用FileMode.Open作为输出文件。再次来自the docs

指定操作系统应打开现有文件。打开文件的能力取决于FileAccess枚举指定的值。如果文件不存在,则抛出FileNotFoundException异常。

这将在文件的开始处打开流。因此,您正在重复在输出文件的开头写入每个部分文件。我确定您注意到您的合并文件大小仅与最大的部分文件一样大。另一方面查看FileMode.Append

打开文件(如果存在)并查找到文件末尾,或创建一个新文件。这需要附加权限。 FileMode.Append只能与FileAccess.Write结合使用。尝试在文件末尾之前寻找位置会引发IOException异常,并且任何读取尝试都会失败并引发NotSupportedException异常。

确定-但要备份更远,

if (!File.Exists(dir))
{
    File.Create(dir).Close();
}
var output = File.Open(dir,FileMode.Open);

...效率低下。为什么我们要检查文件是否存在n次,然后打开/关闭n次?我们可以首先创建文件,然后保持输出流打开,直到将所有数据附加到文件中。

那么,在修复错误时,我们将如何重构您的代码以使用IDisposable?签出using statement。将所有这些放在一起,您的代码可能如下所示:

public void mergeFiles(string dir)
{
    using (FileStream combinedFile = File.Create(dir))
    {
        for (int i = 0; i < parts; i++)
        {
            // Since this string is referenced more than once,capture as a
            // variable to lower risk of copy/paste errors.
            var splitFileName = dir + ".part" + (i + 1);
            using (FileStream filePart = File.Open(splitFileName,FileMode.Open))
            {
                filePart.CopyTo(combinedFile);
            }
            // Note that it's safe to delete the file now,because our filePart
            // stream has been disposed as it is out of scope.
            File.Delete(splitFileName);
        }
    }
}

尝试一下。这是一个完整的工作程序,其中包含一个人为设计的示例,您可以将其粘贴到新的控制台应用程序中并运行:

using System.IO;
using System.Text;

namespace temp_test
{
    class Program
    {
        static int parts = 10;
        static void Main(string[] args)
        {
            // First we will generate some dummy files.
            generateFiles();
            // Next,open files and combine.
            combineFiles();
        }

        /// <summary>
        /// A contived example to generate some files.
        /// </summary>
        static void generateFiles()
        {
            for (int i = 0; i < parts; i++)
            {
                using (FileStream newFile = File.Create("splitfile.part" + i))
                {
                    byte[] info = new UTF8Encoding(true).GetBytes($"This is File # ${i.ToString()}");
                    newFile.Write(info);
                }
            }
        }

        /// <summary>
        /// A contived example to combine our files.
        /// </summary>
        static void combineFiles()
        {
            using (FileStream combinedFile = File.Create("combined"))
            {
                for (int i = 0; i < parts; i++)
                {
                    var splitFileName = "splitfile.part" + i;
                    using (FileStream filePart = File.Open(splitFileName,FileMode.Open))
                    {
                        filePart.CopyTo(combinedFile);
                    }
                    // Note that it's safe to delete the file now,because our filePart
                    // stream has been disposed as it is out of scope.
                    File.Delete(splitFileName);
                }
            }
        }
    }
}

祝您好运,欢迎您使用StackOverflow!