C / C++系统可移植方式更改最大打开文件数

C/C++ System portable way to change maximum number of open files

本文关键字:文件 C++ 系统 可移植 方式更      更新时间:2023-10-16

我有一个C++程序,它转置了一个非常大的矩阵。矩阵太大,无法保存在内存中,因此我将每一列写入单独的临时文件,然后在处理完整个矩阵后连接临时文件。但是,我现在发现我遇到了打开临时文件太多的问题(即操作系统不允许我打开足够的临时文件)。是否有一种系统可移植的方法来检查(并希望更改)允许打开文件的最大数量?

我意识到我可以关闭每个临时文件并仅在需要时重新打开,但我担心这样做对性能的影响。

我的代码工作原理如下(伪代码 - 不保证有效):

int Ncol=5000; // For example - could be much bigger.
int Nrow=50000; // For example - in reality much bigger.
// Stage 1 - create temp files
vector<ofstream *> tmp_files(Ncol);  // Vector of temp file pointers.
vector<string> tmp_filenames(Ncol);  // Vector of temp file names.
for (unsigned int ui=0; ui<Ncol; ui++)
{
    string filename(tmpnam(NULL));  // Get temp filename.
    ofstream *tmp_file = new ofstream(filename.c_str());
    if (!tmp_file->good())
         error("Could not open temp file.n"); // Call error function
    (*tmp_file) << "Column" << ui;
    tmp_files[ui] = tmp_file;
    tmp_filenames[ui] = filename;
 }
 // Stage 2 - read input file and write each column to temp file
 ifstream input_file(input_filename.c_str());
 for (unsigned int s=0; s<Nrow; s++)
 {
       int input_num;
       ofstream *tmp_file;
       for (unsigned int ui=0; ui<Ncol; ui++)
       {
           input_file >> input_num;
           tmp_file = tmp_files[ui];          // Get temp file pointer
           (*tmp_file) << "t" << input_num;  // Write entry to temp file.
       }
 }
 input_file.close();
 // Stage 3 - concatenate temp files into output file and clean up.
 ofstream output_file("out.txt");
 for (unsigned int ui=0; ui<Ncol; ui++)
 {
      string tmp_line;
      // Close temp file
      ofstream *tmp_file = tmp_files[ui];
      (*tmp_file) << endl;
      tmp_file->close();
      // Read from temp file and write to output file.
      ifstream read_file(tmp_filenames[ui].c_str());
      if (!read_file.good())
            error("Could not open tmp file for reading."); // Call error function
      getline(read_file, tmp_line);
      output_file << tmp_line << endl;
      read_file.close();
      // Delete temp file.
      remove(tmp_filenames[ui].c_str());
 }
 output_file.close();

提前非常感谢!

亚当

至少有两个限制:

  • 操作系统可能会施加限制;在Unix(sh,bash和类似的shell)中,使用ulimit在sysadmin允许的范围内更改限制
  • C 库实现也可能有一个限制;您可能需要重新编译库来更改它。

更好的解决方案是避免打开太多文件。在我自己的一个程序中,我围绕文件抽象编写了一个包装器(这是在 Python 中,但在 C 中原理是相同的),它跟踪每个文件中的当前文件位置,并根据需要打开/关闭文件,保留当前打开的文件池。

没有可移植的方法可以更改打开文件的最大数量。像这样的限制往往是由操作系统强加的,因此是特定于操作系统的。

最好的办法是减少一次打开的文件数量。

您可以将输入文件规范化为临时文件,以便每个条目占用相同数量的字符。您甚至可以考虑将该临时文件另存为二进制文件(每个数字使用 4/8 字节,而不是每个十进制数字 1 个字节)。这样,您就可以根据每个条目在矩阵中的坐标计算文件中每个条目的位置。然后,您可以通过执行 std::istream::seekg 来访问特定条目,而不必担心打开文件数量的限制。

只制作 1 个大文件而不是许多小临时文件怎么样? 寻求是一种廉价的操作。 无论如何,您的列都应该是相同的大小。 您应该能够将文件指针放置在访问列所需的位置。

 // something like...
 column_position = sizeof(double)*Nrows*column ;
 is.seekg(column_position) ;
 double column[Nrows] ;
 for( i = 0 ; i < Nrows ; i++ )
    is >> column[i] ;
"

矩阵太大,无法保存在内存中"。不过,矩阵很可能适合您的地址空间。(如果矩阵不适合 2^64 字节,您将需要一个非常令人印象深刻的文件系统来保存所有这些临时文件。因此,不必担心临时文件。让操作系统处理交换到磁盘的工作方式。您只需要确保以交换友好的方式访问内存。在实践中,这意味着你需要有一些参考的地方。但是使用 16 GB 的 RAM,您可以映射 ~400 万页的 RAM。如果你的列数明显小于这个数字,应该没有问题。

(不要为此使用 32 位系统;这不值得痛苦)