C 程序多线程拆分文件

news2025/7/11 17:41:27

C 程序多线程拆分文件

在C语言中,实现多线程来拆分文件通常需要借助多线程库,比如 POSIX 线程库(pthread)或者 Windows 的线程库(CreateThread 或类似的函数)。下面我将分别展示在 Linux 和 Windows 环境下使用这两种方式拆分文件的示例。

在 Linux 下使用 pthread

首先,确保你的系统支持 POSIX 线程

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

/*  定义线程的工作函数    */
void* split_file(void* arg) {
    int thread_id = *((int*)arg);
    FILE* src = fopen("source.txt", "rb");
    if (!src) {
        perror("Failed to open source file");
        return NULL;
    }
    
    fseek(src, 0, SEEK_END);
    long filesize = ftell(src);
    fseek(src, 0, SEEK_SET);
    
    long part_size = filesize / 2; // 简单分割为两半
    long start_pos = thread_id * part_size;
    long end_pos = (thread_id + 1) * part_size;
    if (thread_id == 1) end_pos = filesize; // 确保第二个部分读取剩余部分
    
    char filename[50];
    sprintf(filename, "part%d.txt", thread_id + 1);
    FILE* dest = fopen(filename, "wb");
    if (!dest) {
        perror("Failed to open destination file");
        fclose(src);
        return NULL;
    }
    
    fseek(src, start_pos, SEEK_SET);
    char buffer[1024];
    while (ftell(src) < end_pos) {
        size_t bytes_read = fread(buffer, 1, sizeof(buffer), src);
        fwrite(buffer, 1, bytes_read, dest);
    }
    
    fclose(src);
    fclose(dest);
    return NULL;
}

/*   主函数中创建和管理线程  */
int main() {
    pthread_t threads[2];
    int thread_ids[2] = {0, 1}; // 两个线程,分别处理文件的前半部和后半部
    
    for (int i = 0; i < 2; i++) {
        if (pthread_create(&threads[i], NULL, split_file, &thread_ids[i])) {
            fprintf(stderr, "Error creating thread\n");
            return 1;
        }
    }
    
    for (int i = 0; i < 2; i++) {
        pthread_join(threads[i], NULL);
    }
    
    printf("File split successfully.\n");
    return 0;
}

在 Windows下使用 CreateThread

在Windows环境下,使用CreateThread函数来实现多线程拆分文件是一种常见的方法。CreateThread函数是Windows API的一部分,用于创建一个新的线程。下面,我将详细介绍如何使用CreateThread来实现一个简单的文件拆分程序。

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

/*   定义线程函数   */
DWORD WINAPI SplitFile(LPVOID lpParam) {
    // 定义结构体传递参数
    struct ThreadParams {
        const char* inputFilePath;
        const char* outputFilePath;
        long startPos;
        long length;
    };
 
    // 类型转换参数
    ThreadParams* params = (ThreadParams*)lpParam;
 
    // 打开输入文件和输出文件
    FILE* inputFile = fopen(params->inputFilePath, "rb");
    FILE* outputFile = fopen(params->outputFilePath, "wb");
    if (inputFile == NULL || outputFile == NULL) {
        printf("Error opening file\n");
        return -1;
    }
 
    // 移动到开始位置并读取数据
    fseek(inputFile, params->startPos, SEEK_SET);
    char buffer[1024]; // 定义缓冲区大小
    long bytesRead;
    for (long pos = params->startPos; pos < params->startPos + params->length; pos += bytesRead) {
        bytesRead = fread(buffer, 1, sizeof(buffer), inputFile);
        if (bytesRead > 0) {
            fwrite(buffer, 1, bytesRead, outputFile);
        } else {
            break; // 文件结束或出错时退出循环
        }
    }
 
    // 关闭文件
    fclose(inputFile);
    fclose(outputFile);
    return 0;
}


/* 主函数中创建线程并传递参数
在主函数中,你需要创建多个线程,每个线程处理文件的一部分。你需要计算每个线程应该处理的起始位置和长度  **/
int main() {
    const char* inputFilePath = "largefile.dat";  // 大文件路径
    long fileSize; // 文件大小,单位:字节
    FILE* file = fopen(inputFilePath, "rb");
    if (file == NULL) {
        printf("Error opening file\n");
        return -1;
    }
    fseek(file, 0, SEEK_END); // 移动到文件末尾以获取大小
    fileSize = ftell(file);   // 获取文件大小(字节)
    fclose(file);            // 关闭文件句柄,因为不再需要它读取文件大小了
 
    int numThreads = 4; // 使用4个线程进行拆分,可根据需要调整数量
    long partSize = fileSize / numThreads; // 每部分的大小(字节)
    HANDLE threads[numThreads]; // 线程句柄数组
    struct ThreadParams params[numThreads]; // 参数数组
  
    for (int i = 0; i < numThreads; i++) {
        params[i].inputFilePath = inputFilePath;
        params[i].outputFilePath = malloc(256); // 为每个输出文件分配路径字符串空间(例如:part1.dat, part2.dat等)
        sprintf(params[i].outputFilePath, "part%d.dat", i + 1); // 设置输出文件名
        params[i].startPos = i * partSize; // 计算开始位置
        params[i].length = (i == numThreads - 1) ? fileSize - params[i].startPos : partSize; // 最后一部分可能需要调整长度以覆盖剩余部分
        threads[i] = CreateThread(NULL, 0, SplitFile, &params[i], 0, NULL); // 创建线程并传递参数
    }
  
    // 等待所有线程完成
    WaitForMultipleObjects(numThreads, threads, TRUE, INFINITE); // 等待所有线程完成执行。TRUE表示等待所有对象。INFINITE表示无限等待。
  
    // 清理资源(关闭句柄)和释放分配的内存空间等操作。这里省略具体实现,实际应用中需要
}

附件一:多线程优势

线程程序作为一种多任务、并发的工作方式,当然有其存在优势:

提高应用程序响应:

这对图形界面的程序尤其有意义,当一个操作耗时很长时,整个系统都会等待这个操作,此时程序不会响应键盘、鼠标、菜单的操作,而使用多线程技术,将耗时长的操作(time consuming)置于一个新的线程,可以避免这种尴尬的情况。

使多CPU系统更加有效:

操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。

改善程序结构:

一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。

附件二:操作步骤

线程创建

函数原型:int pthread_create(pthread_t*restrict tidp,const pthread_attr_t *restrict attr,void *(*start_rtn)(void),void *restrict arg);

返回值:若是成功建立线程返回0,否则返回错误的编号。

形式参数:pthread_t*restrict tidp要创建的线程的线程id指针;const pthread_attr_t *restrict attr创建线程时的线程属性;void *(start_rtn)(void)返回值是void类型的指针函数;void *restrict arg start_rtn的形参。

线程挂起:该函数的作用使得当前线程挂起,等待另一个线程返回才继续执行。也就是说当程序运行到这个地方时,程序会先停止,然后等线程id为thread的这个线程返回,然后程序才会断续执行。

函数原型:intpthread_join(pthread_tthread, void **value_ptr);

参数说明如下:thread等待退出线程的线程号;value_ptr退出线程的返回值。

返回值:若成功,则返回0;若失败,则返回错误号。

线程退出

函数原型:voidpthread_exit(void *rval_ptr);

获取当前线程id

函数原型:pthread_t pthread_self(void);

互斥锁

创建pthread_mutex_init;销毁pthread_mutex_destroy;加锁pthread_mutex_lock;解锁pthread_mutex_unlock。

条件锁

创建pthread_cond_init;销毁pthread_cond_destroy;触发pthread_cond_signal;广播pthread_cond_broadcast;等待pthread_cond_wait。

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

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

相关文章

【Linux】Ubuntu Linux 系统——Python集成开发环境

ℹ️大家好&#xff0c;我是练小杰&#xff0c;今天周四了&#xff0c;明天就周五了&#xff0c;再坚持坚持又能休息了&#xff01;&#xff01;&#x1f606; 本文是有关Linux 操作系统中Python集成开发环境基础知识&#xff0c;后续将添加更多相关知识噢&#xff0c;谢谢各位…

数据库加密全解析:从传输到存储的安全实践

title: 数据库加密全解析:从传输到存储的安全实践 date: 2025/2/17 updated: 2025/2/17 author: cmdragon excerpt: 数据加密是数据库安全的最后一道物理防线。传输层SSL/TLS配置、存储加密技术及加密函数实战应用,覆盖MySQL、PostgreSQL、Oracle等主流数据库的20+生产级加密…

【Prometheus】prometheus结合domain_exporter实现域名监控

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…

计算机专业知识【软件开发中的常用图表:E - R图、HIPO、DFD、N - S、PAD详解】

在软件开发过程中&#xff0c;有许多种图表工具被用于不同阶段的设计和分析&#xff0c;帮助开发者更清晰地理解系统结构、数据流程和算法逻辑。下面将详细介绍E - R图、HIPO图、DFD图、N - S图和PAD图&#xff0c;包括它们的样子和用途。 一、E - R图&#xff08;实体 - 联系…

智能马达保护器:为工业电机安全运行保驾护航

在工业生产中&#xff0c;电动机作为核心动力设备&#xff0c;其稳定运行直接关系到生产效率与安全性。然而&#xff0c;复杂的工况环境、频繁启停和突发负载变化&#xff0c;常导致电机面临过载、缺相、短路等故障风险。安科瑞智能马达保护器凭借其智能化、高精度、多功能的设…

深度集成DeepSeek大模型:WebSocket流式聊天实现

目录 5分钟快速接入DeepSeek大模型&#xff1a;WebSocket实时聊天指南创建应用开发后端代码 (Python/Node.js)结语 5分钟快速接入DeepSeek大模型&#xff1a;WebSocket实时聊天指南 创建应用 访问DeepSeek官网 前往 DeepSeek官网。如果还没有账号&#xff0c;需要先注册一个。…

QT基础二、信号和槽

一、什么是信号和槽&#xff1f; 1、简述 在Qt框架中&#xff0c;信号和槽&#xff08;Signals and Slots&#xff09; 是一种用于对象间通信的机制。它是一种非常强大且灵活的设计模式&#xff0c;广泛应用于事件驱动编程中。信号和槽机制允许对象之间以松耦合的方式进行交互…

【深度学习】计算机视觉(CV)-目标检测-Faster R-CNN —— 高精度目标检测算法

1.什么是 Faster R-CNN&#xff1f; Faster R-CNN&#xff08;Region-based Convolutional Neural Network&#xff09; 是 目标检测&#xff08;Object Detection&#xff09; 领域的一种 双阶段&#xff08;Two-Stage&#xff09; 深度学习方法&#xff0c;由 Ross Girshick…

Blazor-父子组件传递任意参数

在我们从父组件传参数给子组件时&#xff0c;可以通过子组件定义的[Parameter]特性的公开属性进行传值&#xff0c;但是当我们需要传递多个值的时候&#xff0c;就需要通过[Parameter]特性定义多个属性&#xff0c;有没有更简便的方式&#xff1f; 我们可以使用定义 IDictionar…

【原创】vue-element-admin-plus完成编辑页面中嵌套列表功能

前言 vue-element-admin-plus对于复杂业务的支持程度确实不怎么样&#xff0c;我这里就遇到了编辑页面中还要嵌套列表的真实案例&#xff0c;比如字典&#xff0c;主字典嵌套子信息&#xff0c;类似于一个树状结构。目前vue-element-admin-plus给出的例子是无法满足这个需求的…

DeepSeek教unity------MessagePack-02

内置支持类型&#xff1a; 对象序列化 MessagePack for C# 可以序列化你自己定义的公共类或结构体类型。默认情况下&#xff0c;可序列化的类型必须用 [MessagePackObject] 属性进行注解&#xff0c;成员需要用 [Key] 属性进行注解。键可以是索引&#xff08;整数&#xff09;…

H5应用抓包及调试技巧

由于图片和格式解析问题&#xff0c;可前往 阅读原文 在现代移动互联网时代&#xff0c;H5 应用以其跨平台、轻量化、快速迭代的特性&#xff0c;成为移动开发的重要一环。然而&#xff0c;随着功能的复杂化和用户体验要求的提升&#xff0c;H5应用的调试也面临着诸多挑战&…

自学Java-面向对象高级(final、单例类、枚举类、抽象类、接口)

自学Java-面向对象高级&#xff08;final、单例类、枚举类、抽象类、接口&#xff09; 一、final关键字1、认识final关键字2、final修饰变量的注意3、常量 二、单例类&#xff08;设计模式&#xff09;1、设计模式的概念2、单例设计模式3、单例类有很多形式4、懒汉式单例类5、小…

docker下部署kong+consul+konga 报错问题处理

前言&#xff1a; 由于在docker下部署一些项目比较特殊&#xff0c;特别是网络这一块&#xff0c;如果没有搞清楚&#xff0c;是很容易出问题的。 先上docker-compose 编排 这里的docker-compose for kong可以在 kong-compose 获取代码 version: 3.9x-kong-config:&kong…

网络优化工作流程

DT路测 移动测试&#xff08;Drive Test&#xff09; CQT 定点测试&#xff08;通信质量测试&#xff09; DT 测试不能体现实际话务质量&#xff1a;回音、串音等网络问题不能通过 DT 测试发现&#xff0c;因此 CQT 拨打测试是 DT 测试很好的补充&#xff0c;也是目前室内外测…

React入门 - 0.React简介

React入门 - React简介 A Brief Introduction to React By JacksonML 1. 关于React React是一个知名的Web框架。众所周知&#xff0c;jQuery, Angular, Vue等框架都曾闪亮登场&#xff0c;并且&#xff0c;都仍然在全球市场占有一席之地。React这个颇有担当的新锐&#xff0…

SpringCloud系列教程:微服务的未来(二十四)Direct交换机、Topic交换机、声明队列交换机

前言 在现代消息队列系统中&#xff0c;交换机是实现消息传递和路由的核心组件。本文将重点探讨三种常见的交换机类型&#xff1a;Direct交换机、Topic交换机和声明队列交换机。通过对这三种交换机的详细分析&#xff0c;我们将学习它们的工作原理、应用场景以及如何在实际项目…

Sojson高级加密技术科普

1. 引言 什么是Sojson&#xff1f; Sojson是一款用于JavaScript代码加密与混淆的工具&#xff0c;它能够有效保护前端代码的知识产权&#xff0c;避免开发者的心血被随意窃取。 为什么需要代码加密&#xff1f; 在当今的互联网环境下&#xff0c;代码被轻易复制、篡改或逆向…

mysql多主集群 galera cluster for mysql 8安装配置启动重启集群

[TOC] 一、安装mysql 1、安装 系统环境&#xff1a; Ubuntu 18.04 64位 MySQL 8.0.19 下载MySQL APT安装配置包 首先访问 https://dev.mysql.com/downloads/repo/apt/ 获取配置包下载地址 wget https://dev.mysql.com/get/mysql-apt-config_0.8.14-1_all.deb sudo dpkg -i mysq…

mybatis 入门案例

前言 我们清楚 mybatis 是一个持久层框架&#xff0c;可以非常便捷的操作数据库。如最常见的对数据进行增删改查操作。 项目准备 1 在mybatis 数据库 创建 user 用户表 并插入以下两条数据 以下是一个user.sql 脚本文件如何使用 脚本文件可以参照MySQL数据库的备份与还原_控…