问题描述
代码:
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!