从txt文件中读取并删除第一行(或最后一行)而不复制

时间:2016-03-01 12:57:35

标签: c++ fstream getline stdstring boost-interprocess

我想从txt文件中读取并删除第一行(不复制,这是一个巨大的文件)。
我已经阅读了网络,但每个人都只是将所需的内容复制到一个新文件中。我做不到。

首次尝试以下。由于没有删除行,此代码将被置于循环中。如果代码将在每个开头删除第一行文件,代码将到达结尾。

if (jQuery().select2)

2 个答案:

答案 0 :(得分:3)

你想要做的事情确实不容易。

如果你打开同一个文件进行阅读和书写而不小心,你最终会阅读你刚写的内容,而结果将不是你想要的。

修改文件是可行的:只需打开它,搜索,修改和关闭即可。但是,您希望在文件开头复制除K个字节之外的文件的所有内容。这意味着您必须按N个字节的块迭代地读取和写入整个文件。

现在完成后,K个字节将保留在需要删除的末尾。我不认为有一种方法可以用流做。您可以使用ftruncate中的truncateunistd.h功能,或使用Boost.Interprocess truncate进行此操作。

这是一个例子(没有任何错误检查,我允许你添加它):

#include <iostream>
#include <fstream>
#include <unistd.h>

int main()
{
  std::fstream file;
  file.open("test.txt", std::fstream::in | std::fstream::out);

  // First retrieve size of the file
  file.seekg(0, file.end);
  std::streampos endPos = file.tellg();
  file.seekg(0, file.beg);

  // Then retrieve size of the first line (a.k.a bufferSize)
  std::string firstLine;
  std::getline(file, firstLine);

  // We need two streampos: the read one and the write one
  std::streampos readPos = firstLine.size() + 1;
  std::streampos writePos = 0;

  // Read the whole file starting at readPos by chunks of size bufferSize
  std::size_t bufferSize = 256;
  char buffer[bufferSize];
  bool finished = false;
  while(!finished)
  {
    file.seekg(readPos);
    if(readPos + static_cast<std::streampos>(bufferSize) >= endPos)
    {
      bufferSize = endPos - readPos;
      finished = true;
    }
    file.read(buffer, bufferSize);
    file.seekg(writePos);
    file.write(buffer, bufferSize);
    readPos += bufferSize;
    writePos += bufferSize;
  }
  file.close();

  // No clean way to truncate streams, use function from unistd.h
  truncate("test.txt", writePos);
  return 0;
}

我真的希望能够为文件的就地修改提供更清晰的解决方案,但我不确定是否存在。

答案 1 :(得分:2)

这是用C语言编写的Windows解决方案。 它将立即执行并完成700,000行,245MB文件。 (0.14秒)

基本上,我将内存映射到文件,以便我可以使用用于原始内存访问的函数来访问内容。一旦文件被映射,我只使用strchr函数来找到用于表示Windows中的EOL的一对符号的位置(\ n和\ r) - 这告诉我们第一行的字节长度是多长

从这里开始,我只是从第一行的第一个字节回忆到内存映射区域的开头(基本上是文件中的第一个字节)。

完成此操作后,文件将被取消映射,关闭mem映射文件的句柄,然后我们使用SetEndOfFile函数将文件长度减少第一行的长度。当我们关闭文件时,它缩小了这个长度,第一行就消失了。

由于我刚刚创建并编写了文件已经在内存中,这显然会稍微改变执行时间,但是Windows缓存机制是这里的“罪魁祸首” - 我们正在利用这个机制进行操作很快完成。

测试数据是重复100,000次的程序源并保存为testInput2.txt(粘贴10次,选择全部,复制,粘贴10次 - 替换原始10次,总共100次 - 重复直到输出足够大。我在这里停下来,因为更多似乎让Notepad ++变得“不开心”

此程序中的错误检查几乎不存在,并且输入预计不是UNICODE,即 - 输入为每个字符1个字节。 EOL序列为0x0D,0x0A(\ r,\ n)

<强>代码:

#include <stdio.h>
#include <windows.h>

void testFunc(const char inputFilename[] )
{
    int lineLength;

    HANDLE fileHandle = CreateFile(
                                    inputFilename,
                                    GENERIC_READ | GENERIC_WRITE,
                                    0,
                                    NULL,
                                    OPEN_EXISTING,
                                    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
                                    NULL
                                    );

    if (fileHandle != INVALID_HANDLE_VALUE)
    {
        printf("File opened okay\n");

        DWORD fileSizeHi, fileSizeLo = GetFileSize(fileHandle, &fileSizeHi);

        HANDLE memMappedHandle = CreateFileMapping(
                                                    fileHandle,
                                                    NULL,
                                                    PAGE_READWRITE | SEC_COMMIT,
                                                    0,
                                                    0,
                                                    NULL
                                                );
        if (memMappedHandle)
        {
            printf("File mapping success\n");
            LPVOID memPtr = MapViewOfFile(
                                            memMappedHandle,
                                            FILE_MAP_ALL_ACCESS,
                                            0,
                                            0,
                                            0
                                          );
            if (memPtr != NULL)
            {
                printf("view of file successfully created");
                printf("File size is: 0x%04X%04X\n", fileSizeHi, fileSizeLo);

                LPVOID eolPos = strchr((char*)memPtr, '\r');    // windows EOL sequence is \r\n
                lineLength = (char*)eolPos-(char*)memPtr;
                printf("Length of first line is: %ld\n", lineLength);

                memcpy(memPtr, eolPos+2, fileSizeLo-lineLength);
                UnmapViewOfFile(memPtr);
            }

            CloseHandle(memMappedHandle);
        }
        SetFilePointer(fileHandle, -(lineLength+2), 0, FILE_END);
        SetEndOfFile(fileHandle);
        CloseHandle(fileHandle);
    }
}

int main()
{
    const char inputFilename[] = "testInput2.txt";
    testFunc(inputFilename);
    return 0;
}