use*_*451 6 c++ fstream getline stdstring boost-interprocess
我想读取并从txt文件中删除第一行(没有复制,这是一个巨大的文件).
我已经阅读了网络,但每个人都只是将所需的内容复制到一个新文件中.我做不到.
低于第一次尝试.由于没有删除行,此代码将被置于循环中.如果代码将在每个开头删除第一行文件,代码将到达结尾.
#include <iostream>
#include <string>
#include <fstream>
#include <boost/interprocess/sync/file_lock.hpp>
int main() {
    std::string line;
    std::fstream file;
    boost::interprocess::file_lock lock("test.lock");
    while (true) {
        std::cout << "locking\n";
        lock.lock();
        file.open("test.txt", std::fstream::in|std::fstream::out);
        if (!file.is_open()) {
            std::cout << "can't open file\n";
            file.close();
            lock.unlock();
            break;
        }
        else if (!std::getline(file,line)) {
            std::cout << "empty file\n"; //
            file.close();                // never
            lock.unlock();               // reached
            break;                       //
        }
        else {
            // remove first line
            file.close();
            lock.unlock();
            // do something with line
        }
    }
}
这是用 C 编写的 Windows 解决方案。它将立即执行并完成一个 700,000 行、245MB 的文件。(0.14 秒)
基本上,我对文件进行内存映射,以便我可以使用用于原始内存访问的函数来访问内容。一旦文件被映射,我只需使用 strchr 函数来查找用于在 Windows 中表示 EOL 的一对符号之一的位置(\n 和 \r) - 这告诉我们第一行的长度(以字节为单位) 。
从这里开始,我只是从第二行的第一个字节memcpy回到内存映射区域的开头(基本上是文件中的第一个字节)。
完成此操作后,文件将取消映射,内存映射文件的句柄将关闭,然后我们使用 SetEndOfFile 函数将文件的长度减少第一行的长度。当我们关闭文件时,它已经缩小了这个长度,并且第一行消失了。
自从我刚刚创建并写入文件以来,该文件已经在内存中,这显然会在一定程度上改变执行时间,但 Windows 缓存机制是这里的“罪魁祸首” - 我们正在利用相同的机制来使操作非常快速地完成。
测试数据是程序源,复制10万次,保存为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;
}
事实上,你想做的事情并不容易。
如果你不小心地打开同一个文件进行读写,那么你最终会读到你刚刚写的内容,而结果将不是你想要的。
就地修改文件是可行的:只需打开它,在其中查找,修改并关闭。但是,您想要复制文件的所有内容(K文件开头的字节除外)。这意味着您将必须按字节块迭代地读取和写入整个文件N。
现在一旦完成,K字节将保留在需要删除的末尾。我认为没有办法用流来做到这一点。为此,您可以使用Boost.Interprocess中的函数ftruncate或使用Boost.Interprocess 。truncateunistd.h 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;
}
我真的很希望能够提供一种更清晰的解决方案来就地修改文件,但我不确定是否有这样的解决方案。
| 归档时间: | 
 | 
| 查看次数: | 5369 次 | 
| 最近记录: |