2014-03-04 40 views
0

我需要将文件的前100个字节移动到文件末尾,然后保存该文件(Windows窗体应用程序)。然后我需要相反的过程(将最后的100个字节移回开头,然后再保存)。将文件的前100个字节移动到文件的末尾,然后再保存并再次保存

其中一些文件非常大(超过2GB),所以我不能使用file.readallbytes,因为我内存不足异常。

我试着玩文件流和使用filestream.position,但我无法包住我的头移动字节,然后保存该文件。

任何指导将不胜感激。

+1

这将涉及物理移动字节。所以你只要读取第101个字节并写入第1个字节即可。然后,第102个到第2个,...然后您将最初存储在某个数组中的前100个字节追加到最后并获得一个赢家啤酒。 – zerkms

+0

我很好,只是使第一个100字节0的,如果这使得它更容易,然后将它们添加到文件的末尾。然后当发生相反的情况时,用结尾的实际值替换那些0字节并删除尾部的100 ... –

回答

3

的关键是使用一个字节缓冲器,所以你仅在一次处理的文件的一小部分。这听起来像你有正确的方法,但一路上有一些陷阱。

下面是示出如何我接近它的一个示例:

public enum SwapType 
{ 
    FrontToBack, 
    BackToFront 
} 

public static class EndSwap 
{ 
    public static void DoSwap(string path, SwapType swapType) 
    { 
     if (path == null) 
     { 
      throw new ArgumentNullException("path", 
       "You must supply a path to the file."); 
     } 
     if (!File.Exists(path)) 
     { 
      throw new FileNotFoundException("File not found."); 
     } 

     string tempPath = Path.GetTempFileName(); 
     byte[] buffer = new byte[4096]; 
     byte[] swapBytes = new byte[100]; 

     using (FileStream inputFs = new FileStream(path, FileMode.Open, 
      FileAccess.Read)) 
     using (FileStream outputFs = new FileStream(tempPath, 
      FileMode.Open, FileAccess.Write)) 
     { 
      int bytesRead = -1; 

      if (swapType == SwapType.FrontToBack) 
      { 
       // We want to keep hold of the first 100 bytes of the file 
       // and output them after copying the rest of file 
       inputFs.Read(swapBytes, 0, 100); 
      } 
      else 
      { 
       // Read the last 100 bytes of the file 
       inputFs.Seek(-100, SeekOrigin.End); 
       inputFs.Read(swapBytes, 0, 100); 
       // Output them straight to the output file 
       outputFs.Write(swapBytes, 0, 100); 
       // Reposition to the beginning of the input file 
       inputFs.Seek(0, SeekOrigin.Begin); 
      } 

      // The number of bytes left to copy is 100 less than the file 
      // length 
      long bytesRemaining = inputFs.Length - 100; 

      // Copy the rest of the bytes 
      while (bytesRemaining > 0) 
      { 
       bytesRead = inputFs.Read(buffer, 0, buffer.Length); 
       // NB: the number of bytes read could be more than the 
       // number remaining 
       outputFs.Write(buffer, 0, 
        (int)Math.Min(bytesRead, bytesRemaining)); 
       bytesRemaining -= bytesRead; 
      } 

      // Don't forget to append the start bytes if required 
      if (swapType == SwapType.FrontToBack) 
      { 
       outputFs.Write(swapBytes, 0, 100); 
      } 
     } 

     // Now swap the files themselves 
     File.Delete(path); 
     File.Move(tempPath, path); 
     // NB: could do File.Replace() if backup is needed 
    } 
} 

实例:

// Copy first 100 bytes to end 
EndSwap.DoSwap(@"C:\Users\Dave\Downloads\MyTest.pdf", SwapType.FrontToBack); 
// Copy those same 100 bytes back to the beginning again 
EndSwap.DoSwap(@"C:\Users\Dave\Downloads\MyTest.pdf", SwapType.BackToFront); 

最终的结果是相同的原始文件,当然。

+0

这是完美的。我希望我可以将这两个答案都标记为正确的,但是由于您提供了如何将其恢复的完整方式,所以这个更好是因为我试图找出另一个答案的返回路径。谢谢。仍然为你们+1 +1) –

4

您不应将所有数据读入内存。通过使用FileStream,您可以读取多个数据块,例如每个1 KB,并将其存储在新文件中。从位置100开始,跳过第一个字节。重新整理完整文件后,在末尾添加跳过的字节。最后将新文件移动到旧文件的位置。通过提高maxBufferSize,您可以固定复制过程,但使用更多的内存。

要恢复更改,请从最后100个字节开始,然后从开始直到inputStream.Length - 100

string inputFile = "C:\\input.txt"; 
string tempFile = "C:\\input.txt"; 
int dataLength = 100; 
int maxBufferSize = 1024; 

using (var inputStream = new FileStream(inputFile, FileMode.Open, FileAccess.Read)) { 
    int length = (int)inputStream.Length; 
    int currentInputPosition = dataLength; 

    inputStream.Position = currentInputPosition; 

    using (var outputStream = new FileStream(tempFile, FileMode.Create, FileAccess.ReadWrite)) { 
     var bufferSize = Math.Min(maxBufferSize, length - currentInputPosition); 

     var buffer = new byte[bufferSize]; 
     while (inputStream.Read(buffer, 0, bufferSize) > 0) { 
      currentInputPosition += bufferSize; 

      outputStream.Write(buffer, 0, buffer.Length); 
     } 

     buffer = new byte[dataLength]; 
     inputStream.Position = 0; 
     inputStream.Read(buffer, 0, buffer.Length); 
     outputStream.Write(buffer, 0, buffer.Length); 
    } 
} 

File.Delete(inputFile); 
File.Move(tempFile, inputFile); 
+0

非常感谢。尽管我对转换有点困惑。我从最后100开始,如下所示:int currentInputPosition = length - 100;并在我的while循环中将这些前100个字节写入新文件。我然后设置我的currentInputPosition = 0;从一开始就开始,但我不确定在哪里放置循环的边界来停止? –

相关问题