C++读取大文件三种方法速度比较

news2024/11/24 10:57:53

目录

  • 测试说明
  • 第一种方法:按块读,一次读8kb
  • 第二种方法:按行读,一次读一行
  • 第三种方法:多线程并行读取
  • 完整示例

测试说明

测试文件:100万行,每一行是两个小数,中间用逗号隔开,读取时每一行的第一个数作为x,第二个数作为y组成两个vector数组。

在这里插入图片描述

第一种方法:按块读,一次读8kb

// 按块大小读取
const size_t BUFFER_SIZE = 20480;  // 8KB 缓冲区大小

std::vector<double> x_large;
std::vector<double> y_large;

void readLargeFile(const std::string& filePath) 
{
    std::ifstream file(filePath, std::ios::binary);

    if (!file)
    {
        std::cerr << "Failed to open file" << std::endl;
        return;
    }

    std::string line;
    std::vector<char> buffer(BUFFER_SIZE);
    while (file.read(buffer.data(), BUFFER_SIZE)) 
    {
        // 在这里处理读取到的缓冲区数据
        for (char c : buffer) 
        {
            if (c == ',')
            {
                x_large.emplace_back(std::stod(line));
                line.clear();
            }
            else if (c == '\n')
            {
                y_large.emplace_back(std::stod(line));
                line.clear();
            }
            else
                line += c;
        }
    }

    // 处理最后不足 BUFFER_SIZE 的部分
    size_t remaining = file.gcount();
    for (size_t i = 0; i < remaining; ++i) 
    {
        if (buffer[i] == ',')
        {
            x_large.emplace_back(std::stod(line));
            line.clear();
        }
        else if (buffer[i] == '\n')
        {
            y_large.emplace_back(std::stod(line));
            line.clear();
        }
        else
            line += buffer[i];
    }

    if (!line.empty())
        std::cout << line << std::endl;

    file.close();
}

测试,这种方法大概需要1800ms左右时间

// 记录开始时间
clock_t start = clock();

readLargeFile("output.txt");    // 1835 1839 1810 1765 1871

// 记录结束时间
clock_t end = clock();

// 计算时间差并转换为毫秒
double elapsedTime = (double)(end - start) * 1000.0 / CLOCKS_PER_SEC;

std::cout << "Function execution time: " << elapsedTime << " milliseconds" << std::endl;

第二种方法:按行读,一次读一行

// 按行读
std::vector<double> x_normal;
std::vector<double> y_normal;
void ReadFileNormal(const std::string& filePath)
{
    std::ifstream file(filePath);

    if (!file)
    {
        std::cerr << "Failed to open file" << std::endl;
        return;
    }

    std::string line;
    while (std::getline(file, line))
    {
        //std::cout << line << std::endl;
        int pos = line.find(',');

        double x = std::stod(line.substr(0, pos));
        double y = std::stod(line.substr(pos + 1, line.size() - pos));

        x_normal.emplace_back(x);
        y_normal.emplace_back(y);
    }

    file.close();
}

测试,大概需要4800ms左右的时间

// 记录开始时间
clock_t start = clock();

ReadFileNormal("output.txt"); // 4878 4772 4821

// 记录结束时间
clock_t end = clock();

// 计算时间差并转换为毫秒
double elapsedTime = (double)(end - start) * 1000.0 / CLOCKS_PER_SEC;

std::cout << "Function execution time: " << elapsedTime << " milliseconds" << std::endl;

第三种方法:多线程并行读取

// 多线程读取
const int NUM_THREADS = 4;  // 线程数量,可以根据文件大小设置

std::vector<std::vector<double>> x(NUM_THREADS);
std::vector<std::vector<double>> y(NUM_THREADS);

std::mutex mtx;

// 每个线程读取文件的部分
void readFilePart(const int& _idx,const std::string& filePath, long long start, long long size) 
{
    std::ifstream file(filePath, std::ios::binary);
    if (!file) 
    {
        std::cerr << "Failed to open file" << std::endl;
        return;
    }

    file.seekg(start);  // 移动到指定位置

    std::vector<char> buffer(size);
    file.read(buffer.data(), size);

    std::vector<double> x1;
    std::vector<double> y1;

    std::string line;
    for (char c : buffer)
    {
        if (c == ',')
        {
            x1.emplace_back(std::stod(line));
            line.clear();
        }
        else if (c == '\n')
        {
            y1.emplace_back(std::stod(line));
            line.clear();
        }
        else
            line += c;
    }

    file.close();

    std::lock_guard<std::mutex> lock(mtx);  // 作用域内加锁,超出作用域自动解锁
	// 按照读取顺序进行赋值
    x[_idx] = x1;
    y[_idx] = y1;
}

void ReadFileThread(const std::string& filePath)
{
    std::ifstream file(filePath, std::ios::ate | std::ios::binary);  // 以二进制模式打开并获取文件末尾位置

    if (!file) 
    {
        std::cerr << "Failed to open file" << std::endl;
        return;
    }

    long long fileSize = file.tellg();  // 获取文件大小
    file.close();

    long long partSize = fileSize / NUM_THREADS;
    std::vector<std::thread> threads;

    for (int i = 0; i < NUM_THREADS; ++i) 
    {
        long long start = i * partSize;
        long long size = (i == NUM_THREADS - 1) ? fileSize - start : partSize;
        threads.emplace_back(readFilePart,i, filePath, start, size);
    }

    for (auto& thread : threads)
        thread.join();
}

测试,开启4个线程并行读取,所需时间大概是580ms左右

// 记录开始时间
clock_t start = clock();

ReadFileThread("output.txt"); // 584 553

// 记录结束时间
clock_t end = clock();

// 计算时间差并转换为毫秒
double elapsedTime = (double)(end - start) * 1000.0 / CLOCKS_PER_SEC;

std::cout << "Function execution time: " << elapsedTime << " milliseconds" << std::endl;

完整示例

#include <iostream>
#include <random>
#include <fstream>
#include <string>
#include <ctime>
#include <thread>
#include <vector>
#include <mutex>

// 随机生成0~10的小数
double GenerateRandomDouble() 
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_real_distribution<double> dis(0.0, 10.0);
    return dis(gen);
}

// 写入文件测试数据
void WriteFile()
{
    std::string filePath = "output.txt";  // 要写入的文件路径

    // 创建并打开文件用于写入,如果文件不存在则创建
    std::ofstream outputFile(filePath, std::ios::app);

    if (outputFile.is_open()) 
    {
        for (int i = 0; i < 1000000; i++)
        {
            double x = GenerateRandomDouble();
            double y = GenerateRandomDouble();

            std::string text = std::to_string(x) + "," + std::to_string(y);

            outputFile << text << std::endl;
        }

        outputFile.close();
    }
    else 
    {
        std::cerr << "无法打开文件进行写入。" << std::endl;
        return;
    }
}

// 按块大小读取
const size_t BUFFER_SIZE = 20480;  // 8KB 缓冲区大小

std::vector<double> x_large;
std::vector<double> y_large;

void readLargeFile(const std::string& filePath) 
{
    std::ifstream file(filePath, std::ios::binary);

    if (!file)
    {
        std::cerr << "Failed to open file" << std::endl;
        return;
    }

    std::string line;
    std::vector<char> buffer(BUFFER_SIZE);
    while (file.read(buffer.data(), BUFFER_SIZE)) 
    {
        // 在这里处理读取到的缓冲区数据
        for (char c : buffer) 
        {
            if (c == ',')
            {
                x_large.emplace_back(std::stod(line));
                line.clear();
            }
            else if (c == '\n')
            {
                y_large.emplace_back(std::stod(line));
                line.clear();
            }
            else
                line += c;
        }
    }

    // 处理最后不足 BUFFER_SIZE 的部分
    size_t remaining = file.gcount();
    for (size_t i = 0; i < remaining; ++i) 
    {
        if (buffer[i] == ',')
        {
            x_large.emplace_back(std::stod(line));
            line.clear();
        }
        else if (buffer[i] == '\n')
        {
            y_large.emplace_back(std::stod(line));
            line.clear();
        }
        else
            line += buffer[i];
    }

    if (!line.empty())
        std::cout << line << std::endl;

    file.close();
}

// 按行读
std::vector<double> x_normal;
std::vector<double> y_normal;
void ReadFileNormal(const std::string& filePath)
{
    std::ifstream file(filePath);

    if (!file)
    {
        std::cerr << "Failed to open file" << std::endl;
        return;
    }

    std::string line;
    while (std::getline(file, line))
    {
        //std::cout << line << std::endl;
        int pos = line.find(',');

        double x = std::stod(line.substr(0, pos));
        double y = std::stod(line.substr(pos + 1, line.size() - pos));

        x_normal.emplace_back(x);
        y_normal.emplace_back(y);
    }

    file.close();
}

// 多线程读取
const int NUM_THREADS = 4;  // 线程数量,可以根据文件大小设置

std::vector<std::vector<double>> x(NUM_THREADS);
std::vector<std::vector<double>> y(NUM_THREADS);

std::mutex mtx;

// 每个线程读取文件的部分
void readFilePart(const int& _idx,const std::string& filePath, long long start, long long size) 
{
    std::ifstream file(filePath, std::ios::binary);
    if (!file) 
    {
        std::cerr << "Failed to open file" << std::endl;
        return;
    }

    file.seekg(start);  // 移动到指定位置

    std::vector<char> buffer(size);
    file.read(buffer.data(), size);

    std::vector<double> x1;
    std::vector<double> y1;

    std::string line;
    for (char c : buffer)
    {
        if (c == ',')
        {
            x1.emplace_back(std::stod(line));
            line.clear();
        }
        else if (c == '\n')
        {
            y1.emplace_back(std::stod(line));
            line.clear();
        }
        else
            line += c;
    }

    file.close();

    std::lock_guard<std::mutex> lock(mtx);  // 作用域内加锁,超出作用域自动解锁
    x[_idx] = x1;
    y[_idx] = y1;
}

void ReadFileThread(const std::string& filePath)
{
    std::ifstream file(filePath, std::ios::ate | std::ios::binary);  // 以二进制模式打开并获取文件末尾位置

    if (!file) 
    {
        std::cerr << "Failed to open file" << std::endl;
        return;
    }

    long long fileSize = file.tellg();  // 获取文件大小
    file.close();

    long long partSize = fileSize / NUM_THREADS;
    std::vector<std::thread> threads;

    for (int i = 0; i < NUM_THREADS; ++i) 
    {
        long long start = i * partSize;
        long long size = (i == NUM_THREADS - 1) ? fileSize - start : partSize;
        threads.emplace_back(readFilePart,i, filePath, start, size);
    }

    for (auto& thread : threads)
        thread.join();
}

int main()
{
    // 记录开始时间
    clock_t start = clock();

    //WriteFile();

    //readLargeFile("output.txt");    // 1835 1839 1810 1765 1871

    //ReadFileNormal("output.txt"); // 4878 4772 4821
    
    ReadFileThread("output.txt"); // 584 553

    // 记录结束时间
    clock_t end = clock();

    // 计算时间差并转换为毫秒
    double elapsedTime = (double)(end - start) * 1000.0 / CLOCKS_PER_SEC;

    std::cout << "Function execution time: " << elapsedTime << " milliseconds" << std::endl;

    system("pause");
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2195653.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python脚本实现Redis未授权访问漏洞利用

之前介绍过Redis未授权访问漏洞&#xff0c;本文使用python实现Redis未授权访问检测以及对应三种getshell。 1 测试环境准备 CentOS 7&#xff08;192.168.198.66/24&#xff09;&#xff1a;安装 Redis 服务器并用 root 权限开启服务&#xff0c;关闭保护模式&#xff1b;安…

4-coumarate--CoA ligase4-香豆酸:辅酶A连接酶4CL-文献精读63

Characterization and Functional Analysis of 4-Coumarate:CoA Ligase Genes in Mulberry 桑树中4-香豆酸&#xff1a;辅酶A连接酶基因的表征与功能分析 桑树T2T基因组-文献精读16 摘要 4-香豆酸&#xff1a;辅酶A连接酶&#xff08;4CL&#xff09;由一个小型的多基因家族…

pytest(六)——allure-pytest的基础使用

前言 一、allure-pytest的基础使用 二、需要掌握的allure特性 2.1 Allure报告结构 2.2 Environment 2.3 Categories 2.4 Flaky test 三、allure的特性&#xff0c;allure.step()、allure.attach的详细使用 3.1 allure.step 3.2 allure.attach&#xff08;挺有用的&a…

软件测试比赛-学习

一、环境配置 二、浏览器适配 //1.设置浏览器的位置,google浏览器位置是默认且固定在电脑里的//2.设置浏览器驱动的位置,C:\Users\27743\AppData\Local\Google\Chrome\ApplicationSystem.setProperty("webdriver.chrome.driver", "C:\\Users\\27743\\AppData\\…

【python实操】python小程序之对象的属性操作

引言 python小程序之对象的属性操作 文章目录 引言一、对象的属性操作1.1 题目1.2 代码1.3 代码解释 二、思考2.1 添加属性2.2 获取属性 一、对象的属性操作 1.1 题目 给对象添加属性 1.2 代码 class Cat:# 在缩进中书写⽅法def eat(self):# self 会⾃动出现,暂不管print(f…

弹性分布式数据集RDD详细说明

文章目录 整体介绍一、定义与特性二、操作与转换三、存储级别与持久化四、依赖关系与容错机制五、优化与性能调优 常见操作支持的数据格式1.文本文件 (Text Files)2. CSV 文件3. JSON 文件4. Parquet 文件5. Sequence Files6.Hadoop文件读取A. 读取HDFS上的文本文件B. 使用Hado…

(Linux驱动学习 - 8).信号异步通知

一.异步通知简介 1.信号简介 信号类似于我们硬件上使用的“中断”&#xff0c;只不过信号是软件层次上的。算是在软件层次上对中断的一种模拟&#xff0c;驱动可以通过主动向应用程序发送信号的方式来报告自己可以访问了&#xff0c;应用程序获取到信号以后就可以从驱动设备中…

论文阅读——联邦忘却学习研究综述

文章基本信息 作者&#xff1a; 王鹏飞魏宗正周东生宋威肖蕴明孙庚于硕张强 机构&#xff1a; 大连理工大学计算机科学与技术学院大连理工大学社会计算与认知智能教育部重点实验室大连大学先进设计与智能计算教育部重点实验室美国西北大学计算机科学系吉林大学计算机科学与…

QT调用libusb库stm32407上下位机

安富莱USB上位机教程 参考安富莱的视频&#xff0c;不过这里 调用是libusb最新的库 可以参考上一个文章&#xff1a; QT调用最新的libusb库 https://editor.csdn.net/md/?articleId142733711 调试结果&#xff1a; 资源地址&#xff1a; 上位机&#xff1a;https://downl…

基于pytorch的手写数字识别-训练+使用

import pandas as pd import numpy as np import torch import matplotlib import matplotlib.pyplot as plt from torch.utils.data import TensorDataset, DataLoadermatplotlib.use(tkAgg)# 设置图形配置 config {"font.family": serif,"mathtext.fontset&q…

Maven 高级之分模块设计与继承、聚合

在软件开发中&#xff0c;随着项目规模的扩大&#xff0c;代码量和复杂度不断增加&#xff0c;传统的一体化开发模式逐渐暴露出诸多问题。为了解决这些问题&#xff0c;模块化开发应运而生&#xff0c;而 Maven 正是模块化开发的利器&#xff0c;它提供的继承和聚合机制为构建和…

fiddler抓包20_弱网模拟

课程大纲 ① 打开CustomRules.js文件&#xff1a;Fiddler快捷键“CtrlR”(或鼠标点击&#xff0c;菜单栏 - Rules - Customize Rules)。 ② 设置速率&#xff1a;“CtrlF”&#xff0c;搜索 “m_SimulateModem”&#xff0c;定位至函数。在函数里设置上传、下载速率&#xff0c…

ESP8266模块(WIFI STM32)

目录 一、介绍 二、传感器原理 1.原理图 2.引脚描述 3.ESP8266基础AT指令介绍 4.ESP8266基础工作模式 三、程序设计 main.c文件 esp8266.h文件 esp8266.c文件 四、实验效果 五、资料获取 项目分享 一、介绍 ESP8266是一款嵌入式系统级芯片&#xff0c;它集成了Wi…

将自己写好的项目部署在自己的云服务器上

准备工作 这里呢我要下载的终端软件是Xshell 如图&#xff1a; 自己准备好服务器&#xff0c;我这里的是阿里云的服务器&#xff0c; 如图&#xff1a; 这两个准备好之后呢&#xff0c;然后对我们的项目进行打包。 如图&#xff1a; 这里双击打包就行了。 找到自己打成jar包…

零基础多图详解图神经网络(GNN/GCN)【李沐论文精读】

A Gentle Introduction to Graph Neural Networks 在上图中&#xff0c;每一层都是一层网络&#xff0c;每一层的节点都受到下一层中自身节点和邻居节点的影响。如果网络比较深&#xff0c;是可以处理到一幅图中较大范围的节点。 前言 图神经网络在应用上还只是起步阶段&…

基于SpringBoot健身房管理系统【附源码】

效果如下&#xff1a; 系统首页界面 系统注册详细页面 健身课程详细页面 后台登录界面 管理员主页面 员工界面 健身教练界面 员工主页面 健身教练主页面 研究背景 随着生活水平的提高和健康意识的增强&#xff0c;现代人越来越注重健身。健身房作为一种专业的健身场所&#x…

日期类的实现(C++)

个人主页&#xff1a;Jason_from_China-CSDN博客 所属栏目&#xff1a;C系统性学习_Jason_from_China的博客-CSDN博客 所属栏目&#xff1a;C知识点的补充_Jason_from_China的博客-CSDN博客 前言 日期类是六个成员函数学习的总结和拓展&#xff0c;是实践的体现 创建文件 构造函…

HCIP--以太网交换安全(二)

端口安全 一、端口安全概述 1.1、端口安全概述&#xff1a;端口安全是一种网络设备防护措施&#xff0c;通过将接口学习的MAC地址设为安全地址防止非法用户通信。 1.2、端口安全原理&#xff1a; 类型 定义 特点 安全动态MAC地址 使能端口而未是能Stichy MAC功能是转换的…

在VMware WorkStation上安装飞牛OS(NAS系统)

对于NAS系统&#xff0c;小白相信很多小伙伴都不陌生&#xff0c;在许多场景下也能看得到&#xff0c;它其实可以算是文件存储服务器&#xff0c;当然&#xff0c;你如果给它加上其他服务的话&#xff0c;它也能变成网页服务器、Office协同办公服务器等等。 有许多小伙伴都拿这…

信息安全工程师(38)防火墙类型与实现技术

一、防火墙类型 按软、硬件形式分类 软件防火墙&#xff1a;通过软件实现防火墙功能&#xff0c;通常安装在个人计算机或服务器上&#xff0c;用于保护单个设备或小型网络。硬件防火墙&#xff1a;采用专门的硬件设备来实现防火墙功能&#xff0c;通常部署在企业网络边界或数据…