如何将文本文件分解成更小的块(在 Unix 上使用 C++)?

Posted

技术标签:

【中文标题】如何将文本文件分解成更小的块(在 Unix 上使用 C++)?【英文标题】:How could I decompose a text file in smaller chunks (using C++ on Unix)? 【发布时间】:2021-11-29 17:17:44 【问题描述】:

我正在做一项学校作业,我必须使顺序代码并发。代码所做的称为MapReduce,更具体地说,它计算所有单词在所有输入文件中出现的次数。

输入:包含所有要处理的文本文件的目录。 输出:包含带有结果的文本文件的目录。

我们给出的实现由 4 个阶段组成;拆分地图洗牌和减少。前 3 个必须在它们之间同时发生,当所有 3 个都完成后,Reduce 就会发生。

并发,除了发生在这三个阶段之间,还必须发生在每个阶段内。为了做到这一点,我们被告知在一定数量的线程之间分配工作(每个阶段都有它的线程)。

从现在开始,我将只讨论拆分和地图阶段,它们是 我现在遇到问题的那些。

Split 和 Map 阶段将有一个线程用于每个“分区”(它们将具有相同数量的线程,因为每个 Split 线程都会关联一个 Map 线程),并且每个文件都有一个“分区”输入目录,除了大文件,我必须每 8 MB 生成一个“分区”

这个异常是我要解决的问题,让我再解释一件事,我会解决的。

由于 Split 和 Map 必须具有相同数量的线程,我所做的是创建一个函数来计算必须创建的分区数量,以便能够告诉 Split 和 Map 有多少线程当我启动它们时,它们必须创建。

Split 线程所做的是获取它们已分配的“分区”(如果其大小小于 8 MB,它将是一个完整的文件)并将其逐行发送到其关联的 Map 线程(通过将它们写入线程安全队列)。

好的,这是我的问题,我想让 Map 线程(从提到的队列中读取并用每一行做他们的事情,现在并不重要)从队列中读取,直到他们读取 EOF,这意味着它关联的拆分线程已结束将其“分区”写入队列,但这仅适用于代表整个文件的“分区”。

所以,我的问题是:

    我必须使用哪些选项将文件分解为 8 MB 的块? 如何让一个线程知道何时停止读取? 由于 Map 线程将在一小部分时间内尝试从队列中读取,但拆分线程尚未写入任何内容,我如何让它们“等待”队列中写入的内容?

这是计算需要多少线程的函数,我想让它生成一个文件描述符数组,每个“分区”包含一个文件描述符

int MapReduce::getSplitNum()
int split_num = 0;
char file_path[264];

DIR* dir = opendir(InputPath);
struct dirent* entity;
unsigned char isFile =0x8; // El valor que pren entity->d_type quan es tracta d'un fitxer

while ((entity = readdir(dir)) != NULL)

    // Evitem el directori que conté els fitxers (.) i el directori anterior (..).
    if( strcmp(entity->d_name, ".")!=0 && strcmp(entity->d_name, "..")!=0 && entity->d_type == isFile )
    
        struct stat file_status;
        sprintf(file_path,"%s/%s",InputPath, entity->d_name);
        stat(file_path, &file_status);

        long file_size = file_status.st_size;

        // DEBUG: printf("Fitxer: %s\t Mida: %ld\n", entity->d_name, file_status.st_size);
        if (file_size < MAX_SPLIT_SIZE)
           
            split_num++;
        
        else
        
            long restant = file_size - MAX_SPLIT_SIZE;
            split_num = split_num + 2; // Sumem 2 perquè al ser un arxiu gran com a mínim usarà 2 splits, més els que vagi afegint el bucle while.

            while (restant > MAX_SPLIT_SIZE)
            
                restant = restant - MAX_SPLIT_SIZE;
                split_num++;
            
        
    

closedir(dir);
return split_num;

我想会有很多分解文件的方法,但我很想知道哪种方法是“好的做法”。

谢谢!

【问题讨论】:

【参考方案1】:

也许是这样的?此函数将文件分解成相等的部分,最后一个是不同的(文件的其余部分)。这可以修改为将文件分解为特定大小的块。我刚刚写了这个,它似乎对我有用,但当然还需要进一步的测试。当然,我不确定这是否是最佳解决方案。这会产生 n 个名为 0, 1, ..., n 的文件。

#include <iostream>
#include <fstream>

void decompose_file (const std::string& filepath, const int number_of_files) 
    std::ifstream infile(filepath);

    infile.seekg(0, std::ios::end);
    size_t length = infile.tellg();
    infile.seekg(0, std::ios::beg);
    
    for (int i = 0; i < number_of_files; ++i) 
        char * buffer;
        size_t chunk_size = 0;
        if (i != number_of_files - 1) 
            chunk_size = length / number_of_files;
        
        else 
            chunk_size = length - ((number_of_files - 1) * (length / number_of_files));
        
        buffer = new char[chunk_size];
        
        infile.read (buffer, chunk_size);
        
        std::ofstream outfile (std::to_string(i));
        if (outfile.is_open()) 
            outfile.write(buffer, chunk_size);
            outfile.close();
        
        delete[] buffer;
    
    infile.close();


int main (int argc, char* argv[]) 
    decompose_file("my_file.txt", 4);
    return 0;

【讨论】:

以上是关于如何将文本文件分解成更小的块(在 Unix 上使用 C++)?的主要内容,如果未能解决你的问题,请参考以下文章

分解成更小的查询

将 PL/pgSQL 函数分解成更小的部分

将巨大的(95Mb)JSON 数组拆分成更小的块?

如何在Python中优化计算大数

在 Java 中生成更小的 code-128 条码

如何一次滚动绘制每个 SVG 路径(按时间顺序)?