C++ 文件有 32K 整数,由换行符分隔。我需要创建 8 个较小的文件,每个文件包含 4096 个整数

C++ File has 32K ints seperated by newline. I need to create 8 smaller files to each hold 4096 ints

我有一个由换行符分隔的整数文件。

324872
27
256230
0
45767
276143
4
258283
189
153812
214521

文件大小为 32768 行。我需要将它分成 8 个 4096 行的小文件。我使用 fstream 将原始文件流式传输到字符缓冲区中:

std::string fileOfInts(".txt");
char *buffer = new char[BUFFER_SIZE];
std::ifstream inputFromOrigin("origin.txt");
int fileIndex = 0;
while (inputFromOrigin)
{
    inputFromOrigin.read(buffer, BUFFER_SIZE);
    size_t count = inputFromOrigin.gcount();
    if (!count)
        break;

    std::ofstream createRunSizeFile;
    createRunSizeFile.open("fileOfInts" + std::to_string(fileIndex) + fileOfInts);
    int value;
    if (createRunSizeFile) {
        for (size_t i = 0, bufferSize = sizeof(buffer); i < bufferSize; i += sizeof(int)) {
            value = (int)buffer[i];
            createRunSizeFile << value << std::endl;
        }
    }
    createRunSizeFile.close();
    fileIndex++;
}
inputFromOrigin.close();
delete[] buffer;

但是当我从 char 缓冲区中提取整数时,它一次只读取两位数字并将这两位数字放在一个文件中,所以我最终得到 54 个文件,每个文件包含一个整数:

32

更新:

当我更改从缓冲区分配值的 for 循环时:

for (int i = 0; i < BUFFER_SIZE; i++)

我得到每个文件 4096 个唯一行,但我得到 53 个文件,每行两位数字,而不是 8 个具有相同值的文件:

10
49
57
57
54
48
50

如何解析 char 缓冲区以将 4096 个唯一的整数放入每个文件?

更新 - 解决方案:

对于将来可能遇到此挑战的其他人,以下是我如何将 David 的解决方案应用到我现有的代码中:

int fileIndex = 1;
int lineIndex = 0;
std::string line = "";
std::ofstream createRunSizeFile;
// loop through origin file line by line
while (getline(inputFromOrigin, line)) {
    // when file is 0 or 4066 lines long create a new file
    if (lineIndex % RUN == 0) {
        createRunSizeFile.open("fileOfInts" + std::to_string(fileIndex) + fileOfInts);
        lineIndex = 0;
        if (createRunSizeFile.is_open()) {
            createRunSizeFile.close();
        }
        // open new run size file and increment file counter
        createRunSizeFile.open("fileOfInts" + std::to_string(fileIndex++) + fileOfInts);
        if (!createRunSizeFile.good()) {
            std::cerr << "Error: Run Size File Failed to Open" << std::endl;
            return 1;
        }
    }
    // assign line from origin to the run size file
    createRunSizeFile << line << std::endl;
    lineIndex++;
}
inputFromOrigin.close();

我做了一个错误的假设,即从字符缓冲区中提取整数比逐行提取更容易。这个解决方案正是我现在需要它做的。

而不是使用 .read,只需使用 getline 即可将包含整数的行读入字符串。然后只需保留一个行计数器并提出一些方案来为输出文件名编写后缀并打开输出文件并将 4096 行写入文件,重置行计数器,打开下一个文件并重复,直到 运行 超出要阅读的行数。

你可以#define一个常量表示每个子文件的行数,或者声明一个,然后声明你的计数器(fileno以下只是用作子文件后缀),声明一个字符串用作缓冲区来保存从输入读取的行,然后是你的两个文件——打开输入文件:

#include <iostream>
#include <fstream>
#include <string>

#define NLINES 4096     /* constant no. of lines for output subfiles */

int main (int argc, char **argv) {

    if (argc < 2) { /* validate at least 1 argument for filename */
        std::cerr << "usage: " << argv[0] << " filename\n";
        return 1;
    }

    size_t  n = 0,              /* line counter */
            fileno = 1;         /* output file suffix */
    std::string s {};           /* string to use as buffer */
    std::ifstream f (argv[1]);  /* open input file stream */
    std::ofstream subf;         /* output file stream */

    if (!f.good()) { /* validate input file stream stat/e good */
        std::cerr << "error: input file open failed.\n";
        return 1;
    }

要拆分文件,只需将每一行读入 s 并检查行计数器的 模数 是否为零。如果是这样,创建你的下一个输出文件名,将你的行计数器重置为零,检查你的输出文件是否打开,如果是,关闭它,然后使用新的输出文件名打开输出文件,验证它是否打开,那么它就是将字符串写入输出文件并递增行计数器,例如

    while (getline (f, s)) {        /* read each line from input file into s */
        if (n % NLINES == 0) {      /* if 0 or 4096 */
            /* create output filename "subfile_X" */
            std::string fname = { "subfile_" + std::to_string(fileno++) };
            n = 0;                  /* reset line count 0 */
            if (subf.is_open())     /* if output file open - close it */
                subf.close();
            subf.open (fname);      /* open new output file */
            if (!subf.good()) {     /* validate output file stream state good */
                std::cerr << "error: file open failed '" << fname << "'.\n";
                return 1;
            }
        }
        subf << s << '\n';      /* write s to output file */
        n++;                    /* increment line count */
    }

这就是您真正需要的。将各个部分缝合在一起即可得到完整的程序:

#include <iostream>
#include <fstream>
#include <string>

#define NLINES 4096     /* constant no. of lines for output subfiles */

int main (int argc, char **argv) {

    if (argc < 2) { /* validate at least 1 argument for filename */
        std::cerr << "usage: " << argv[0] << " filename\n";
        return 1;
    }

    size_t  n = 0,              /* line counter */
            fileno = 1;         /* output file suffix */
    std::string s {};           /* string to use as buffer */
    std::ifstream f (argv[1]);  /* open input file stream */
    std::ofstream subf;         /* output file stream */

    if (!f.good()) { /* validate input file stream stat/e good */
        std::cerr << "error: input file open failed.\n";
        return 1;
    }

    while (getline (f, s)) {        /* read each line from input file into s */
        if (n % NLINES == 0) {      /* if 0 or 4096 */
            /* create output filename "subfile_X" */
            std::string fname = { "subfile_" + std::to_string(fileno++) };
            n = 0;                  /* reset line count 0 */
            if (subf.is_open())     /* if output file open - close it */
                subf.close();
            subf.open (fname);      /* open new output file */
            if (!subf.good()) {     /* validate output file stream state good */
                std::cerr << "error: file open failed '" << fname << "'.\n";
                return 1;
            }
        }
        subf << s << '\n';      /* write s to output file */
        n++;                    /* increment line count */
    }
}

具有 32k 整数的示例输入文件

$ wc -l < dat/32kint.txt
32768

示例使用

不太精彩:

$ ./bin/filesplit dat/32kint.txt

生成的子文件

$ for i in subfile*; do printf "%s - " "$i"; wc -l < "$i"; done
subfile_1 - 4096
subfile_2 - 4096
subfile_3 - 4096
subfile_4 - 4096
subfile_5 - 4096
subfile_6 - 4096
subfile_7 - 4096
subfile_8 - 4096

八个文件,每个文件 4096 行。检查一下,如果您有任何问题,请告诉我。