linux C++ -使用内存Map增加系统中文件的大小[duplicate]

llmtgqce  于 2023-03-07  发布在  Linux
关注(0)|答案(1)|浏览(133)

此问题在此处已有答案

Increasing a file's size using mmap(1个答案)
5天前关闭。

问题和预期结果

我正在尝试读入一个文件,看看是否可以将该数据写入另一个非空文件。最后,我希望能够将数据插入到该文件中,但这是另一个问题。现在,我能够写入该文件,但文件的大小不会更改。例如,给定以下文件
test.dat

Name,marker1,marker2,marker3,marker4
barc1,AA,AB,BB,--
barc2,AB,AA,BB,--

如果我尝试写入以下数据
test.dat.toAdd

barc3,BB,AB,--,AA
barc4,AB,--,BB,AA
barc5,--,AB,AA,BB
barc6,BB,AA,AB,--
barc7,AA,AB,BB,AA
barc8,BB,AB,AA,BB

从15字节开始,我希望得到

Name,marker1,mabarc3,BB,AB,--,AA
barc4,AB,--,BB,AA
barc5,--,AB,AA,BB
barc6,BB,AA,AB,--
barc7,AA,AB,BB,AA
barc8,BB,AB,AA,BB

但实际上我最后
test.dat

Name,marker1,mabarc3,BB,AB,--,AA
barc4,AB,--,BB,AA
barc5,--,AB,AA,BB
barc

因此,它只写入test.dat最初的大小

代码

下面是我使用的代码my_write.cpp

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <sstream>
#include <unistd.h>

// Opens up [filename] after [offset] bytes and returns a pointer in memory to the beginning of [filename] + [offset]
char* open_mmap_file_read(const char* filename, long long offset, long long& filesize) {
  // Open the file in read-only mode
  const char* my_file = filename;
  int fd = open(my_file, O_RDONLY);
  if (fd < 0) { std::cerr << "Cannot open the file " << my_file << std::endl; }

  // Get the filesize (and possibly error) of the file opening. Filesize is in bytes
  struct stat statbuf;
  int err = fstat(fd, &statbuf);
  off_t sz = statbuf.st_size;
  if (err < 0) { std::cerr << "Cannot open the file " << my_file << " because of fstat val " << err << std::endl; return NULL; }
  std::cout << "File size for " << my_file << " is " << sz << " bytes" << std::endl;

  // Map the file into memory with a pointer to the beginning of the file
  void *fileArea = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
  if (! fileArea) { std::cerr << "Cannot map " << my_file << std::endl; return NULL; }
  std::cout << "File " << my_file << " mapped to address " << fileArea << std::endl;

  // Move the pointer according to the [offset] parameter in memory
  char *localArea = reinterpret_cast<char*>(fileArea);
  if (! localArea) { std::cerr << "Cannot allocate " << sz << " bytes" << std::endl; return NULL; }
  localArea += offset;

  // Store the filesize for use when function returns
  filesize = sz;

  return localArea;
}

// Opens [filename] and writes [data_to_write] in [filename] starting at [offset] bytes. The amount of data to be written is [size_data_to_write]
char* open_mmap_file_write(const char* filename, long long offset, char* data_to_write, long long size_data_to_write, long long& filesize) {
  // Open the file in read/write mode
  const char* my_file = filename;
  int fd = open(my_file, O_RDWR);
  if (fd < 0) { std::cerr << "Cannot open the file " << my_file << std::endl; }

  // Get the filesize (and possibly error) of the file opening. Filesize is in bytes
  struct stat statbuf;
  int err = fstat(fd, &statbuf);
  off_t sz = statbuf.st_size;
  if (err < 0) { std::cerr << "Cannot open the file " << my_file << " because of fstat val " << err << std::endl; return NULL; }
  std::cout << "File size for " << my_file << " is " << sz << " bytes" << std::endl;
  filesize = sz;

  // Map the file into memory with a pointer to the beginning of the file
  void *fileArea = mmap(NULL, offset + size_data_to_write, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  //void *fileArea = mmap(NULL, 200, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  if (! fileArea) { std::cerr << "Cannot map " << my_file << std::endl; return NULL; }
  std::cout << "File " << my_file << " mapped to address " << fileArea << std::endl;

  // Move the pointer according to the [offset] parameter in memory
  char *localArea = reinterpret_cast<char*>(fileArea);
  if (! localArea) { std::cerr << "Cannot allocate " << sz << " bytes" << std::endl; return NULL; }
  localArea += offset;

  // Copy [data_to_write] into the memory mapping of [filename] starting from [offset] bytes
  //ssize_t n = write(fd, data_to_write, size_data_to_write);
  void* copiedArea = memcpy(localArea, data_to_write, size_data_to_write);

  // Return a pointer to the beginning of the file
  return reinterpret_cast<char*>(fileArea);
}

int main(int argc, char *argv[]) {
  if (argc < 4) {
    std::cerr << "Please provide two command-line arguments: file_to_open (string) and file_offset (integer), file_to_add (string)" << std::endl;
    return 1;
  }

  // Get the filename and offset parameters and make sure offset is valid
  const char* file_to_open = argv[1];
  const char* arg_file_offset = argv[2];
  const char* file_to_add = argv[3];
  std::istringstream iss(arg_file_offset);
  long long file_offset;
  if (!(iss >> file_offset)) { std::cerr << "Cannot convert command-line argument " << arg_file_offset << " into an integer for file offset" << std::endl; return 1; }

  long long file_to_add_size; // Pass this by reference to the following function to keep track of filesize
  char* file_to_add_pointer = open_mmap_file_read(file_to_add, 0, file_to_add_size);
  // Print out the first 20 characters from where the file start pointing
  for (int i = 0; i < 20; i++) { std::cout << file_to_add_pointer[i]; } std::cout << std::endl;
  std::cout << std::endl;

  long long file_size;
  char* file_pointer = open_mmap_file_write(file_to_open, file_offset, file_to_add_pointer, file_to_add_size, file_size);
  // Print out all the characters that were written to the memory-mapping
  for (int i = 0; i < file_offset + file_to_add_size; i++) { std::cout << file_pointer[i]; } std::cout << std::endl;
  std::cout << std::endl;

  return 0;
}

它使用./my_write test.dat 15 test.dat.toAdd运行
所以我的问题是,我如何“扩展”文件以容纳正在写入的全部数据。它正在写入内存(正如我们可以从main函数中的print看到的),甚至正在写入文件,但它会根据文件大小被截断。我确信这是一个简单的修复,但我似乎找不到如何告诉系统扩展文件的内存

nr9pn0ug

nr9pn0ug1#

目标文件不足以存储所有test.dat.toAdd + 15字节。
您可以使用ftruncateopen_mmap_file_write中扩展它:

// ...
    std::cout << "File size for " << my_file << " is " << sz << " bytes"
              << std::endl;

    // Add this --- start ---
    auto new_minimum_size = offset + size_data_to_write;
    if(new_minimum_size > sz) {
        if(ftruncate(fd, new_minimum_size) == -1) {
            std::perror("ftruncate");
            return nullptr;
        }
        sz = new_minimum_size;
    }
    // Add this --- end ---

    filesize = sz;
    //...

相关问题