【问题标题】:C# Combine Archive Divided Into One FileC# 合并归档为一个文件
【发布时间】:2020-08-31 10:09:19
【问题描述】:

代码:

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...”以便以后提取它们。

当我使用上述功能时,存档已损坏。
我已经为此苦苦挣扎了一周,在网上寻找,但这是我找到的最佳解决方案,但它不起作用。

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

【问题讨论】:

  • 在关闭之前尝试一个 output.Flush()。输入和输出的文件大小应该完全相同。关闭可能不会将缓冲区中的所有数据写入输出文件。
  • 它没有帮助,存档仍然损坏。

标签: c# file gzip divide


【解决方案1】:

您的代码存在一些问题。如果您查看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!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    • 2012-03-11
    • 1970-01-01
    • 2017-08-22
    • 1970-01-01
    相关资源
    最近更新 更多