windows环境,多线程情况下,C语言向文件写入数据。

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了windows环境,多线程情况下,C语言向文件写入数据。相关的知识,希望对你有一定的参考价值。

具体如下:
我试图向一个某文件中追加数据,最初写法是
FILE *fp = fopen(path,"a");
……
fclose(fp);
若单个运行做出的程序,追加1W个数据,可以实现
但如果有多个同样的程序运行,向同一个文件追加数据,会出现数据丢失的情况。
我记得可以在追加数据的时候锁定文件,避免数据丢失的情况,但是,貌似没弄成功
我希望求一个实例,要求如下:
1运行环境 Window
2要求能用GCC编译通过
3要求完整例子,包括:打开文件、锁定文件、输入数据、解除锁定、关闭文件
五个步骤
4如果可以,请尽量用FILE *fp = fopen(path,"a");打开
但实在不行,用CreatFile也可以 无论如何,请用 C/C++编写
5如果编写的代码符合工整,我会追加50分作为报酬
多谢前辈大神帮助
又PS:lilaosi2001先生的程序看起来很棒的样子,但我windows程序设计显然没学好,如果能把那几个涉及到API的宏解释下(比如“GENERIC_READ、GENERIC_WRITE”),那就更好了。。当然,即便您不愿下,我也一定会给您200分的
而lieyan2024先生,您觉得,不断地尝试打开文件再写入快呢,还是打开后不断尝试写入快呢?
twknq94 先生,请不要ctrl+C,ctrl+V.我没有用过goto,本专业的人都知道

①、对于你能写这么长的问题描述,说明你很认真。

②、你的目的性较强,但是你也想有更加明确的目标,我可以给你讲一下怎么自己去寻找目标和路线以及怎样学习。

③、计算机专业领域一共有几个大方向,十几个分支方向,而每个分支方向又有几十个小方向,每一个方向的深入学习与熟练到一定火候都不是一朝一夕,互相之间也不是完全没联系的,但是你现在就应该选择一个大方向并在其中的一个小方向内深入(为什么要这么早就选择具体的分支方向?后面说)。

④、这里列出计算机的几个大方向(非编程开发类的我就不说了):
基本方向:
1、单片机、嵌入式方向
2、网络编程:涉及到服务器程序、客户端开发、脚本设计等。
3、系统编程:基础API开发、桌面开发、系统程序开发、服务程序
4、图形学:3D、2D、图像识别、人脸识别
5、音频:语音识别、音频解码、音频软件
6、编译原理:编译器设计、脚本解释器、虚拟机、非自然语言翻译系统
7、应用层开发:利用高层语言去开发表层应用
8、安全:反工程、病毒、反病毒、木马、反木马、软件破解、软件加壳
附加方向:
8、人工智能:遗传算法、神经网络、灰色系统等等
9、游戏设计:各种游戏引擎设计以及业务逻辑设计等

⑤、基本方向是你一定要选的,附加方向只是基于基本方向的一些锦上添花,但是不管你怎么选,最开始某些东西一定要深入而不是只是懂就够(当然你对自己要求似乎不会很低),我把这个列出来:

数据结构:下面其他理论的基础。
操作系统原理:理解操作系统的架构和细节,你才能对以后关于多线程、文件管理、内存管理、指令优先级等有一个正确理解和运用。
编译原理:能够升华你对计算机编程语言的理解,对以后出现的各种编译、解释、兼容、移植、优化、并发与并行算法等有一个深入理解。
数据库系统原理:这个是进入公司都要会的,也是大型软件开发的基础。
软件工程:这个是你能够在经验不足还能保证大项目正常完成的理论基础。
网络技术:这个是必须学的,因为目前几乎没有一款装几率很高的软件或者平台跟网络无关。

数学的话,主要是:离散数学、线性代数、高等数学、计算机图形学、概率论

以上几个基础就是你成为一个融汇各个主要分支牛人必须学的(当然不是指理论,而是理论+实践编码能力)

⑥以上都是大的基础,要一一攻破并深入学习,虽然网络时代计算机专业知识爆炸式的增长,但是以上几个基础掌握后,会发现,以后的什么新的理论和技术都是基于这些大基础,你就很容易理解了。

⑦我为什么开头不讲你要具体学什么怎么顺序学呢?因为那些技术你要掌握的话,根本可以自己解决,但是如果你由于兴趣,沉迷于一些自己可见的小范围技术的话,那么毕业后虽然也能找到不错的工作,薪水也可能高,但是不能成为一个大牛。

现在才开始讲学习顺序,虽然你说不要推荐书,不过我还是要用书来做顺序。
C语言是可以写很多核心和高级的东西,而不只是小东西,但是从你代码来看,居然用到了 goto,我不是说你那些程序用到GOTO有什么不好,而是一定要避免用GOTO,goto是错误之源,如果你有什么内容非要用到goto才能写到,说明你的编码技巧还有不少提高空间。

你的学习顺序应该是:
C:做一个超级马里奥出来,并能够读取文本脚本来更新关卡。
C++:写一个2D图形引擎,封装掉细节,实现面向对象设计和可复用设计,并且用到《设计模式》中提到的一些设计模式,这样才能算对C++有一个很好的掌握。
MFC:MFC技术虽然近期已经冷下来了,但是你能熟练掌握它,才能证明你的C++OO技术够纯熟,严格证明你掌握了MFC很简单,你只要用MFC做出一个杀毒引擎就差不多了。推荐的书有《深入浅出MFC》。
《Windows程序设计》:和MFC不同的是,用的是windows核心SDK,也就是API,这本书学完后,你才能从操作系统层面上算掌握了win32 平台下的机理(其实win64和win32大部分机理类似)。
C#:C#里集合了当代和前沿计算机科学里最先进的一些语法(虽然执行效率一直被人质疑),但是你学完C#并深入后,至少能够算是对计算机语言有一个更加深刻的理解了。如何证明你C#学的不错了?也很简单,再次写一个随便什么游戏,比如俄罗斯方块。如果更加证明自己呢?用它写一个P2P网络对战游戏。

(如果你注意的话,会发现我说的学习顺序都是沿着语言和某些技术的,为什么呢?因为这些语言和技术涉及到特定的领域技术和计算机理论思想,比如学完了C#的话,就不单指学完了C#,而是把多种语言范式都学习了一遍,以及现代的程序开发思维(因为里面用到了很多让你一劳永逸的技术))

以上5个步骤都是基础大步骤,要解决的话要没1-2年应该不够。
与此同时,要尽快选出文中你感兴趣的方向作为3-5年的长期方向,不要担心过早选择分支方向会有什么损失,因为计算机很多分支是相通的,只有你把分支方向深入进去,才能真正理解很多理论的实践意义。并且一旦你在某个分支领域形成了较强的优势(比如,到公司里只有你这方面最强),那么你就是稀缺人才。

关于大方向的步骤就不说了,你主要就是要把我说的这几个基础步骤先解决,同时平时要注重大方向理论结合实际去编码和开发。
参考技术A 下面的程序,编译之后,你可以运行很多个实例,目前我将文件写在了D:\1.txt,每个程序写1000行数据,这些值你可以自己更改(比如 写在C:,每个程序写10000行等),等程序都写完后,你可以去文件中查看写文件的结果。补充一下,我是在VC6.0环境中写的,所以windows.h,如果你不是在这个环境中的话,可能需要修改一些定义,比如DWORD等。其他的API都是windows平台提供的API;
#include <stdio.h>
#include "windows.h"
int main()

//获取进程ID,因为你希望是多个进程运行同时写一个文件,所以,我们打印出进程ID
DWORD dwProcessID = GetCurrentProcessId();

//初始化我们要写入文件中的内容,及该内容长度;
char szContent[100] = 0;
sprintf(szContent,"process[%u] write file\r\n",dwProcessID);
DWORD dwContentLen = strlen(szContent);

//创建互斥量,这样可以进行进程间的互斥,当然用这个也可以做线程间的互斥
HANDLE hMutex = CreateMutex(NULL,FALSE,"MyFileMutex");
if (NULL == hMutex)

printf("[%u]Create/Open Mutex error!\r\n",dwProcessID);
return 1;


//创建或打开文件
HANDLE hFile = CreateFile("D:\\1.txt",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_ARCHIVE,
NULL);
if (INVALID_HANDLE_VALUE == hFile)

printf("[%u]Creat/Open file error!\r\n",dwProcessID);
return 1;


//循环写入文件
for(int i = 0; i < 1000 ; i++)

//等待临界资源,即锁定文件
WaitForSingleObject(hMutex,INFINITE);
printf("Process[%u] Get the signal\r\n",dwProcessID);
DWORD len = 0;

//因为是共享写文件,即多个程序写一个文件,所以一定要将文件指针偏移到尾部
SetFilePointer(hFile,0,NULL,FILE_END);

//写入文件
BOOL rnt = WriteFile(hFile,szContent,dwContentLen,&len,NULL);
if (rnt == FALSE)

printf("Process[%u] Fail to write file\r\n",dwProcessID);


//释放互斥量,解除锁定
ReleaseMutex(hMutex);

//加个Sleep便于我们中间观察结果
Sleep(30);

CloseHandle(hMutex);
CloseHandle(hFile);
return 0;


应你要求,我把AIP中的宏定义解释如下:
HANDLE hFile = CreateFile("D:\\1.txt",
GENERIC_READ | GENERIC_WRITE,//表示程序对该文件有读和写的权限
FILE_SHARE_WRITE | FILE_SHARE_READ,//表示可以多个程序共享读和写的权限
NULL,
OPEN_ALWAYS,//表示打开该文件,如果该文件不存在,则创建该文件
FILE_ATTRIBUTE_ARCHIVE,//文件的属性为存档
NULL);

WaitForSingleObject(hMutex,INFINITE);
//INFINITE表示永远等待,直到hMutex有信号为止

SetFilePointer(hFile,0,NULL,FILE_END);
//FILE_END表示从文件尾部开始偏移;实际此举就是将文件指针偏移到文件尾部;本回答被提问者采纳
参考技术B 丢失的问题是程序设计的问题,你写文件实际上只能是向一个写,这个磁盘的物理结构决定的。如果你要多个数据来源的话,就设计一个异步的buffer,写文件时向这个buffer写入,另外一个单独的线程就检查这个buffer,发现有数据就向文件中追加。这样设计就不会丢失数据了。

接口类似:
class AsyncBuffer

virtual bool isEof() = 0;
virtual void write(const unsigned char* data, unsigned int size) = 0;
virtual unsigned int read(unsigned char* buff, unsigned int szBuf) = 0;
;

使用如下:
AsyncBuffer asyncBuff;

thread1:
asyncBuf.write(...);

thread2:
asyncBuf.write(...);

write file thread:
FILE* fp = fopen(...);
while(!end)

if(asyncBuf.isEof()) Sleep(10);
asyncBuf.read(....);
fwrite(...);

fclose(fp);
参考技术C .......
补充:
.......
又补充:
大约一个正常人都会认为这个公式是正确的:打开 + 写入 > 写入。
这说明楼主你是对的。
既然有了正确答案,那我们也就不再继续深究了。

linux下c语言实现多线程文件复制

转自:https://www.cnblogs.com/zxl0715/articles/5365989.html

1、具体思路
把一个文件分成N份,分别用N个线程copy,
每个线程只读取指定长度字节大小的内容
最后一个线程的源文件所指定的结束位置是文件的实际大小
每个线程读取指定源文件部分的起始位置和结束位置的内容到缓冲区
每个线程将缓存中的内容写入目的文件的指定开始位置和结束位置
主线程必须等到所有线程copy完成后才能退出
 
2.有关文件操作的函数
2.1. 文件的打开和关闭
2.1.1 open()函数 
       open()函数的作用是打开文件, 其调用格式为: 
         int open(char *filename, int access);  
  该函数表示按access的要求打开名为filename的文件, 
  返回值为文件描述字
  open()函数打开成功, 返回值就是文件描述字的值(非负值), 否则返回-12.1.2 close()函数 
       close()函数的作用是关闭由open()函数打开的文件, 其调用格式为:
          int close(int handle);  
       该函数关闭文件描述字handle相连的文件。 
2.2.读写函数 
2.2.1 read()函数 
       read()函数的调用格式为:
          int read(int handle, void *buf, int count);  
       read()函数从handle(文件描述字)相连的文件中, 读取count个字节放到buf所指的缓冲区中, 
       返回值为实际所读字节数, 返回-1表示出错。返回0 表示文件结束。
 
2.2.2 write()函数 
       write()函数的调用格式为:
          int write(int handle, void *buf, int count);  
 
       write()函数把count个字节从buf指向的缓冲区写入与handle相连的文件中,
       返回值为实际写入的字节数
2.3.随机定位函数 
lseek()函数 
       lseek()函数的调用格式为: 
         int lseek(int handle, long offset, int fromwhere);  
       该函数对与handle相连的文件位置指针进行定位, 功能和用法与fseek() 函数相同。
 
3.源文件(copyfn.c)
源文件在ubuntu10.04下编译通过
 
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
 
#define THREADS_COUNT 3
#define THREADS_BUFF_SIZE 1*1024
struct thread_block

    int infd; ///源文件句柄
    int outfd;//目的文件句柄
    size_t start;///文件的写入起始位置
    size_t end; ///文件写入的终止位置
;
 
void usage()

    printf("copy %%src %%dst\\n");

///获取文件大小
size_t get_filesize(int fd)

    struct stat st;
    fstat(fd,&st);
    return st.st_size;

void *thread_copy_fn(void *arg);
int main(int argc,char *argv[])

    if(argc < 3)
    
        usage();    
        return -1;
    
    ///打开文件
    int infd = open(argv[1],O_RDONLY);
    int outfd = open(argv[2],O_CREAT|O_WRONLY,0644);
    // 0644也就是-文件所有者有读写权限,组有读权限,其他用户有读权限
    if(infd == -1|| -1 ==outfd)
    
        printf("error while open file \\n");
        return -1;
    
    size_t file_size = get_filesize(infd);
 
    size_t thread_size = THREADS_COUNT;
    struct thread_block *blocks = (struct thread_block *)
        malloc(sizeof(struct thread_block )* thread_size);
    size_t percent = file_size / thread_size;
    printf("filesize = %d\\t percent_blocks = %d\\n",            file_size,percent);
    int i = 0;
    //init-thread-block
    for(; i < thread_size;++i)
    
        blocks[i].infd = infd;
        blocks[i].outfd = outfd;
        blocks[i].start = i * percent;
        blocks[i].end = blocks[i].start + percent;
    
    //the last thread
    blocks[i].end = file_size;
    pthread_t ptid[thread_size];    
    ///创建线程
    for(i = 0 ; i < thread_size; ++i)
    
        pthread_create(&ptid[i],NULL,thread_copy_fn,&(blocks[i]));
    
    ///线程Join
    for(i = 0 ; i < thread_size; ++i)
   
        pthread_join(ptid[i],NULL);
    
    ///释放资源
    free(blocks);
    close(infd);
    close(outfd);
    printf("Copy Successfully \\n");
    return 0;

 
void *thread_copy_fn(void *arg)

    struct thread_block *block = (struct thread_block *)arg;
    char buf[THREADS_BUFF_SIZE];    
    int ret;
    size_t count = block->start;
 
    printf("In Thread\\t%ld\\nstart = %ld\\t end = %ld\\n",            pthread_self(),block->start,block->end);
 
    ///lseek到同样的位置
    ret = lseek(block->infd,block->start,SEEK_SET);
    ret = lseek(block->outfd,block->start,SEEK_SET);
    int bytes_read;
    int bytes_write;
    while(count < block->end)
    
        bytes_read = read(block->infd,buf,sizeof(buf));
        if(bytes_read >0)
        
            printf("thread = %ld\\t read = %ld\\t count %d\\n",                    pthread_self(),bytes_read,count);
            count += bytes_read;
 
            //read()返回-1,同时errno为EINTR,表示读的过程中遇到了中断
            if((bytes_read == -1)&&(errno !=EINTR))
                    break;
            char *ptr_write = buf;
            while((bytes_write = write(block->outfd,ptr_write,bytes_read))!=0)
            
                //write()会返回-1,同时errno为EINTR,表示在写的过程中遇到了中断
                if((bytes_write == -1)&&(errno!=EINTR))
                    break;
                if(bytes_write == bytes_read)
                    break;
                else if(bytes_write > 0)
                
                    ptr_write += bytes_write;
                    bytes_read -= bytes_write;
                
                printf("thread = %ld\\t write = %ld\\t read %d\\n",                    pthread_self(),bytes_write,bytes_read);
            //end-write;
            ///error while write
            if(bytes_write == -1)
                break;
            
        
    
    printf("#####Thread exit %ld#####\\n",pthread_self());
    pthread_exit(NULL); 
 
本文欢迎转载,转载请注明作者与出处

 

以上是关于windows环境,多线程情况下,C语言向文件写入数据。的主要内容,如果未能解决你的问题,请参考以下文章

linux下c语言实现多线程文件复制

C语言复习之直接向文件中写入和读取时间Date对象

用C语言如何实现多线程同时运行的情况下,各个线程输出不同的随机数?

C语言怎么写线程代码

C语言中 怎么实现双线程 或者 父子线程啊

linux下c语言简单实现写日志函数(多线程安全)