【问题标题】:shift first 100 bytes of a file to the end of the file and save then back again and save again将文件的前 100 个字节移到文件末尾并保存,然后再次返回并再次保存
【发布时间】:2014-04-06 16:25:07
【问题描述】:

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

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

我尝试过使用文件流并使用 filestream.position,但我无法动脑筋移动字节然后保存文件。

任何指导将不胜感激。

【问题讨论】:

  • 它将涉及物理移动字节。因此,您只需读取第 101 个字节并将其写入第 1 个字节。然后是第 102 到第 2,... 然后将最初存储在某个数组中的前 100 个字节附加到末尾,并获得优胜者啤酒。
  • 我可以将前 100 个字节设为 0,如果这样更容易,然后将它们添加到文件末尾。然后当相反的情况发生时,用最后的实际值替换那些 0 字节并删除尾部的 100...

标签: c# bytearray filestream


【解决方案1】:

关键是使用字节缓冲区,这样您一次只处理文件的一小部分。听起来您的方法是正确的,但在此过程中存在一些问题。

这是一个展示我如何处理它的示例:

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);

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

【讨论】:

  • 这是完美的。我希望我可以将这两个答案都标记为正确,但是由于您提供了如何取回它的完整方法,所以这个更好,因为我一直试图找出另一个答案的返回路径。谢谢。仍然为你们俩 +1 :)
【解决方案2】:

您不应该将所有数据都读入内存。通过使用 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);

【讨论】:

  • 非常感谢。不过,我对转换回来有点困惑。我从最后 100 个开始,如下所示: int currentInputPosition = length - 100;并执行我的 while 循环将前 100 个字节写入新文件。然后我设置我的 currentInputPosition = 0;从头开始,但我不确定在哪里放置循环停止的边界?
猜你喜欢
  • 2014-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多