代码:
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个部分,我想得到这个文件。
问题是我不知道如何组合这些文件"文件.gz.part1…";以便稍后提取。
当我使用上述功能时,档案已损坏
我已经在网上找了一个星期了,但这是我找到的最好的解决方案,它不起作用。
有人对如何将归档部分合并为一个文件有什么建议吗
您的代码有一些问题。如果您查看System的文档。IO.Stream.Close你会看到以下备注(重点是我的(:
关闭当前流并释放与当前流关联的任何资源(如套接字和文件句柄(与其调用此方法,不如确保正确地处理了流
因此,根据文档,您希望处理您的流,而不是直接调用close
(我稍后再谈(。忽略这一点,你的主要问题就在这里:
var output = File.Open(dir, FileMode.Open);
您正在使用FileMode.Open
作为输出文件。再次从文档:
指定操作系统应打开现有文件。打开文件的能力取决于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次?我们可以在第一步创建文件,并保持输出流打开,直到我们将所有数据附加到它
那么,在修复bug的同时,我们如何重构代码以使用IDisposable呢?查看using语句。把所有这些放在一起,你的代码可能看起来像这样:
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!