使用O_CREAT、O_WRONLY获取文件当前位置并追加数据及socket写入文件问题
问题分析与修复方案
嘿,我看你代码里的核心问题一眼就找到了——你用了O_TRUNC这个标志!这玩意儿会在打开文件时直接清空所有现有内容,所以每次运行代码等于把旧文件删了重写,自然每次都是“新建”文件的效果,第一步必须把它删掉。
接下来一步步给你修复代码,同时解答你关于文件位置和追加的疑问:
1. 先把文件打开的标志改对
把打开文件的代码改成这样:
fd = open("/home/regs_p/cprograms/tcp/RSA.c", O_WRONLY | O_APPEND | O_CREAT, 0644);
- 去掉
O_TRUNC:彻底避免清空原有文件 - 加上
0644权限:用O_CREAT时必须指定文件权限,不然会生成权限全空的文件(连自己都可能打不开) O_APPEND已经帮你搞定了追加逻辑:所有写操作都会自动定位到文件末尾,完全不需要手动找位置
2. 优化文件指针的使用逻辑
你现在每次循环里都调用fdopen(fd, "a+"),这是个低级错误——同一个文件描述符反复调用fdopen会生成多个独立的FILE指针,而且你从不关闭,会造成内存和文件资源泄漏。应该把fdopen移到循环外面,只打开一次:
if (fd < 0) { printf("Some problem with the file!"); } else { // 只初始化一次FILE指针,用"a"模式就够了(只写追加) fp = fdopen(fd, "a"); if (fp == NULL) { printf("Failed to open file stream!"); close(fd); // 出错时别忘了关闭文件描述符 return; } while ((b = read(sockfd, buffer, sizeof(buffer) - 1)) > 0) { // 重点:用实际读取到的字节数b来写,不是sizeof(buffer)! // 不然buffer没读满的话,会把后面的垃圾数据也写进文件 fwrite(buffer, 1, b, fp); // 可选:立即刷新缓冲区,确保数据实时写入文件(默认是缓冲到一定量才写) fflush(fp); // 获取当前文件位置,直接用ftell就行 size = ftell(fp); // 可以加个打印验证:printf("Current file offset: %ld\n", size); } // 用完一定要关闭,资源泄漏是大忌 fclose(fp); close(fd); }
这里要特别注意fwrite的参数:你之前写的fwrite(buffer, sizeof(buffer), 1, fp)是把整个buffer当作一个元素写,但实际上你从socket只读到了b个字节,应该改成fwrite(buffer, 1, b, fp)——意思是写b个大小为1字节的元素,这样才是正确写入实际收到的数据。
3. 关于获取文件当前位置的疑问
当你用O_APPEND打开文件描述符,或者用"a"/"a+"打开FILE指针时,系统会自动保证所有写操作都在文件末尾,完全不需要手动调用fseek或者lseek。
如果确实需要手动获取当前位置:
- 对FILE指针用
ftell(fp),返回的是从文件开头到当前位置的字节数 - 对文件描述符用
lseek(fd, 0, SEEK_CUR),同样返回当前偏移量
另外多说一句:如果不用O_APPEND,想手动跳到末尾写,那可以用lseek(fd, 0, SEEK_END),但O_APPEND是原子操作,多进程/线程同时写文件时不会出现内容覆盖的问题,比手动seek安全多了。
额外提醒
- 你的
fd是static的,要注意如果这个函数被多次调用,别重复打开文件(可以在打开前先检查fd是否已经大于0) read返回0表示客户端断开了连接,返回-1是出错,最好也处理这些情况,避免死循环- 如果是传输文本数据,确保socket传来的内容是正确的,但
fwrite是按字节写的,不管文本还是二进制都没问题
内容的提问来源于stack exchange,提问作者Ace.McCloud
相关产品推荐
相关产品推荐

