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