0

好的,我制作了一个 C# winform 应用程序,它是一个 File_Splitter_Joiner。您只需给它一个文件,它就会为您将其拆分为您指定的多个部分。拆分在单独的线程中完成。在我切片 1Gig 文件之前,一切都运行良好!在任务管理器中,我看到我的程序开始消耗 1G 内存,我的电脑差点死机!不仅如此,切片完成后,消耗并没有改变!(不知道这是否意味着垃圾收集器不工作,虽然我很确定我丢失了对持有大数据块的所有引用,所以它应该工作)这是 Splitter 构造函数(只是为了给你一个更好的主意):

public FileSplitter(string FileToSplitPath, string PiecesFolder, int NumberOfPieces, int PieceSize, SplittingMethod Method)
{
  FileToSplitInfo = new FileInfo(FileToSplitPath);
  this.FileToSplitPath = FileToSplitPath;
  this.PiecesFolder = PiecesFolder;
  this.NumberOfPieces = NumberOfPieces;
  this.PieceSize = PieceSize;
  this.Method = Method;
  SplitterThread = new Thread(Split);
}

这是进行实际拆分的方法:(我还是个新手,所以你即将看到的“可能不会”以最好的方式完成,我只是在这里学习)

private void Split()
{
  int remainingSize = 0;
  int remainingPos = -1;
  bool isNumberOfPiecesEqualInSize = true;
  int fileSize = (int)FileToSplitInfo.Length; // FileToSplitInfo is a FileInfo object
  if (fileSize % PieceSize != 0)
  {
    remainingSize = fileSize % PieceSize;
    remainingPos = fileSize - remainingSize;
    isNumberOfPiecesEqualInSize = false;
  }
  byte[] fileBytes = new byte[fileSize];
  var _fs = File.Open(FileToSplitPath, FileMode.Open);
  BinaryReader br = new BinaryReader(_fs);
  br.Read(fileBytes, 0, fileSize);
  br.Close();
  _fs.Close();

  for (int i = 0, index = 0; i < NumberOfPieces; i++, index += PieceSize)
  {
   var fs = File.Create(PiecesFolder + "\\" + Path.GetFileName(FileToSplitPath) + "." + (i+1).ToString());
   var bw = new BinaryWriter(fs);
   bw.Write(fileBytes, index, PieceSize);
   if(i == NumberOfPieces-1 && !isNumberOfPiecesEqualInSize && Method == SplittingMethod.NumberOfPieces)
   bw.Write(fileBytes, remainingPos, remainingSize);
   bw.Close();
   fs.Close();
  }
 MessageBox.Show("File has been splitted successfully!");
 SplitterThread.Abort();
}

现在,我不是通过 BinaryReader 读取文件的字节,而是首先通过该File.ReadAllBytes方法读取它,它适用于小文件大小,但是,当我与我们的大家伙打交道时,我遇到了“SystemOutOfMemory”异常,不知道为什么当我通过 BinaryReader 读取字节时没有得到那个异常。

(这是一个介于两者之间的问题)

所以,主要问题是,我怎样才能以不消耗太多内存的方式加载大文件(讲演出)?我的意思是,我怎样才能让我的程序不消耗所有的内存?以及如何在拆分完成后释放已使用的内存?(我实际上用过

bw.Dispose; fs.Dispose; 

代替

bw.Close(); fs.Close(); 

是一样的。我知道 Q 可能没有意义,因为当我们加载某些东西时,它会进入我们的记忆而不是其他地方,但是,我这样问的原因是因为我使用了另一个 Splitting_Joining 程序(不是我写的)只是为了看看如果它有同样的问题,我加载了文件,程序消耗了大约 5Migs 的内存,当我开始拆分时,它使用了大约 10Migs !现在这是一个非常大的区别.. 可能那个应用程序是 C/C++ ..

所以总结一下,谁很烂?它是我的代码吗?如果是,我该如何解决?还是在性能方面是 C#?

非常感谢你能帮我搞定的任何事情:)

4

2 回答 2

2

以下两行将杀死您:

int fileSize = (int)FileToSplitInfo.Length; // a FileInfo object
...
byte[] fileBytes = new byte[fileSize];
  1. 当大小结束时,您的代码将失败Int32.MaxValue。没必要,直接用long fileSize = FileToSplitInfo.Length;
  2. 当没有足够的连续内存时,此更正的代码将失败。(LOH的)碎片化迟早会让你失望。
  3. 您为整个文件分配内存,但PieceSize一次只需要字节。

您甚至不需要知道文件大小,只需

byte[] pieceBuffer = new byte[PieceSize];

while (true)
{
    int nBytes = br.Read(pieceBuffer, 0, pieceBuffer.Length);
    if (nBytes == 0) 
       break;

    // write this piece, the length is nBytes 
}
于 2012-09-06T21:58:53.463 回答
1

有不同的方面可以做得更好:

  • 如果您正在使用大文件,为什么要先读取数组中的所有内容,然后再写入另一个文件?只需在读取另一个文件时写入新文件。

  • 用于using保证流的处置,在任何情况下:要么有例外,要么没有。

  • 如果您开始使用非常大的文件,例如 1GB 甚至更大,我建议您查看 Memory Mapped Files。因此,您将获得令人难以置信的内存消耗优势和一些增加的性能成本。

于 2012-09-06T21:56:07.147 回答