当前位置: 首页 > news >正文

ngx_write_file

1 定义

ngx_write_file 函数 定义在 ./nginx-1.24.0/src/os/unix/ngx_files.c
ssize_tngx_write_file(ngx_file_t*file,u_char*buf,size_tsize,off_toffset){ssize_tn,written;ngx_err_terr;ngx_log_debug4(NGX_LOG_DEBUG_CORE,file->log,0,"write: %d, %p, %uz, %O",file->fd,buf,size,offset);written=0;#if(NGX_HAVE_PWRITE)for(;;){n=pwrite(file->fd,buf+written,size,offset);if(n==-1){err=ngx_errno;if(err==NGX_EINTR){ngx_log_debug0(NGX_LOG_DEBUG_CORE,file->log,err,"pwrite() was interrupted");continue;}ngx_log_error(NGX_LOG_CRIT,file->log,err,"pwrite() \"%s\" failed",file->name.data);returnNGX_ERROR;}file->offset+=n;written+=n;if((size_t)n==size){returnwritten;}offset+=n;size-=n;}#elseif(file->sys_offset!=offset){if(lseek(file->fd,offset,SEEK_SET)==-1){ngx_log_error(NGX_LOG_CRIT,file->log,ngx_errno,"lseek() \"%s\" failed",file->name.data);returnNGX_ERROR;}file->sys_offset=offset;}for(;;){n=write(file->fd,buf+written,size);if(n==-1){err=ngx_errno;if(err==NGX_EINTR){ngx_log_debug0(NGX_LOG_DEBUG_CORE,file->log,err,"write() was interrupted");continue;}ngx_log_error(NGX_LOG_CRIT,file->log,err,"write() \"%s\" failed",file->name.data);returnNGX_ERROR;}file->sys_offset+=n;file->offset+=n;written+=n;if((size_t)n==size){returnwritten;}size-=n;}#endif}
`ngx_write_file` 函数 用于向文件写入指定长度的数据,支持从指定偏移量开始写入。 它内部循环处理部分写入和 `EINTR` 信号中断,保证数据完整写入; 若系统支持 `pwrite` 则直接使用(不改变文件位置), 否则通过 `lseek` 定位后调用 `write`,并维护文件位置缓存。 写入成功时返回实际写入字节数, 失败时返回 `NGX_ERROR`。

2 详解

1 函数签名

ssize_tngx_write_file(ngx_file_t*file,u_char*buf,size_tsize,off_toffset)
返回值类型:ssize_t 成功时:返回实际写入文件的字节数(非负整数)。 这个值可能等于请求的 size,也可能小于 size (但在该函数实现中,除非出错,否则会循环直到写完,所以通常等于 size)。 失败时:返回 NGX_ERROR
参数: ngx_file_t *file 指向 nginx 封装的文件结构体。 u_char *buf 指向要写入的数据缓冲区的起始地址 size_t size 指定期望写入的字节数 off_t offset 指定写入操作的起始位置(绝对偏移)。 函数会将数据写入文件的该偏移处,而不受当前文件指针的影响。

2 逻辑流程

1 局部变量 2 文件写入 2-1 支持 pwrite 2-2 不支持 pwrite

1 局部变量
{ssize_tn,written;ngx_err_terr;written=0;
n 临时存储每次系统调用(pwrite 或 write)的返回值。 在循环中,n 表示本次实际写入的字节数。 written 累积已成功写入的总字节数 初始化为 0

2 文件写入
2-1 支持 pwrite
#if(NGX_HAVE_PWRITE)for(;;){n=pwrite(file->fd,buf+written,size,offset);if(n==-1){err=ngx_errno;if(err==NGX_EINTR){ngx_log_debug0(NGX_LOG_DEBUG_CORE,file->log,err,"pwrite() was interrupted");continue;}ngx_log_error(NGX_LOG_CRIT,file->log,err,"pwrite() \"%s\" failed",file->name.data);returnNGX_ERROR;}file->offset+=n;written+=n;if((size_t)n==size){returnwritten;}offset+=n;size-=n;}
#1 NGX_HAVE_PWRITE 宏定义 判断系统是否支持 pwrite 系统调用。若支持,则编译此分支代码 pwrite 可以在指定偏移量写入数据,且不改变文件当前偏移量, 避免多线程/多进程写同一文件描述符时产生竞争
#2 无限循环,用于处理可能的部分写入和 EINTR 中断, 直到所有数据写入完成或遇到不可恢复的错误。 pwrite 不保证一次写入全部数据,且可能被信号中断(EINTR),因此需要循环重试。
#3 调用 pwrite 系统调用, 从 buf + written 处开始写入 size 字节到文件描述符 file->fd 的 offset 偏移位置。 参数详解: file->fd:文件描述符。 buf + written:当前待写入数据的起始地址(written 记录已写入的字节数)。 size:本次期望写入的字节数(循环中逐渐减少)。 offset:本次写入的绝对偏移量(循环中逐渐增加)。 返回值:成功时返回实际写入的字节数(ssize_t),失败时返回 -1 并设置 errno。
#4 判断系统调用是否失败。 获取当前的系统错误码,保存到局部变量 err 中 判断错误码是否为 EINTR(系统调用被信号中断)。 EINTR 是可恢复的临时错误,应该重试而不是报错。 记录调试日志,表明 pwrite 被中断,但会重试 记录严重错误日志,指明 pwrite 失败,并输出文件名。 对于其他错误(非 EINTR),记录错误后函数将返回失败。
#5 更新 nginx 内部维护的文件偏移量 file->offset,加上本次实际写入的字节数。 file->offset 用于 nginx 上层模块跟踪当前文件位置,保持一致性。 累积已写入的总字节数到局部变量 written。 用于计算剩余待写数据,并最终作为返回值。 判断本次实际写入的字节数是否等于本次期望写入的字节数(即 size) 如果本次写入完成了所有请求的字节,则函数返回累积写入的总字节数。 所有数据已成功写入,正常退出。
#6 更新下一次 pwrite 的偏移量,加上本次写入的字节数。 因为还有剩余数据未写入,需要将后续数据写入到紧接的位置。 减少剩余待写入的字节数。 调整循环条件,继续写入剩余部分。 循环结束,回到 for (;;) 继续下一次迭代

2-2 不支持 pwrite
#elseif(file->sys_offset!=offset){if(lseek(file->fd,offset,SEEK_SET)==-1){ngx_log_error(NGX_LOG_CRIT,file->log,ngx_errno,"lseek() \"%s\" failed",file->name.data);returnNGX_ERROR;}file->sys_offset=offset;}for(;;){n=write(file->fd,buf+written,size);if(n==-1){err=ngx_errno;if(err==NGX_EINTR){ngx_log_debug0(NGX_LOG_DEBUG_CORE,file->log,err,"write() was interrupted");continue;}ngx_log_error(NGX_LOG_CRIT,file->log,err,"write() \"%s\" failed",file->name.data);returnNGX_ERROR;}file->sys_offset+=n;file->offset+=n;written+=n;if((size_t)n==size){returnwritten;}size-=n;}#endif}
#1 当系统不支持 pwrite 时, nginx 使用 lseek + write 的组合来实现偏移量写入, 并缓存文件系统偏移量以减少 lseek 调用。
#2 检查缓存的文件系统偏移量 file->sys_offset 是否与目标写入偏移量 offset 一致 file->sys_offset 记录了当前文件指针的实际位置。 如果位置不符,则需要先 lseek 定位到目标偏移,避免每次写入都进行 lseek 系统调用(性能优化)。
#3 调用 lseek 将文件指针移动到 offset 处(绝对定位)。 返回值:成功时返回新偏移量;失败时返回 -1。 将缓存的文件系统偏移量更新为当前文件指针位置(即 offset)。
#4 无限循环,用于处理部分写入和 EINTR。 调用 write 系统调用,从 buf + written 处写入 size 字节到当前文件指针位置。 注意:与 pwrite 不同,write 不指定偏移量,而是使用当前文件位置,并自动更新位置。
http://www.jsqmd.com/news/538109/

相关文章:

  • 盘点推荐:2026年AI智能CRM系统主流品牌 - SaaS软件-点评
  • 解决洛雪音乐源下载异常:从诊断到优化的完整指南
  • Gemini vs 文心一言 2026深度评测:国内AI大模型谁更适合开发者?
  • TIA博途中安装V90驱动器的HSP支持包提示出错无法安装的处理办法
  • JRebel最新版避坑指南:从安装到Debug的完整配置流程(2023实测)
  • 大疆L1点云与ContextCapture融合实战:从Sbet轨迹到三维建模的完整数据处理链路
  • Translumo终极指南:三分钟掌握实时屏幕翻译神器的完整教程
  • 颠覆窗口管理:Topit让Mac多任务效率提升200%
  • Pulse_PWM库:嵌入式LED呼吸灯非阻塞控制实现
  • 告别复杂配置!5分钟用Ollama搞定Phi-3-mini-4k-instruct本地部署
  • Umi-OCR插件架构深度解析:多引擎集成与性能优化实践
  • 南京高端腕表翻新服务详解:38个奢华品牌修复指南+六城专业门店实测(含2026数据) - 时光修表匠
  • 2025_NIPS_DreamVLA: A Vision-Language-Action Model Dreamed with Comprehensive World Knowledge
  • 光伏MPPT之灰狼算法:应对局部遮阴与光照突变
  • OpenClaw安全防护指南:nanobot本地化部署的权限管理
  • 立知-lychee-rerank-mm效果展示:文本+图像联合匹配惊艳案例集
  • RePKG资源处理工具:Wallpaper Engine开发者的格式解析与转换解决方案
  • SDMatte+与标准版切换策略:何时该用增强版?响应时间与显存占用对比
  • LeaguePrank:5分钟学会英雄联盟个性化美化工具终极指南 [特殊字符]
  • 2026年云储存哪个好用?5款免费又便捷的工具深度盘点
  • 找工作什么软件好?2026招聘APP排行榜,高效靠谱不踩坑 - 博客万
  • 别再用yield了!FastAPI 2.0官方弃用警告下的流式响应新范式(含ASGI StreamingResponse + async iterator最佳实践)
  • Git远端修改过账号密码,本地无法推送的解决方法
  • 10:L应用联邦学习:蓝队的分布式安全协作
  • Zotero Night:告别夜间阅读烦恼的终极解决方案
  • 避开Kaggle糖尿病预测的常见坑:数据预处理、特征解读与模型调优实战指南
  • 2K2000龙芯主板以科技创新为驱动力,赋能产业高质量发展
  • 谷歌下场、牛津融资:人形机器人开始从“会动”卷到“真能落地”
  • 实战指南:华为光猫配置解密工具深度解析与高效应用
  • 头皮精华用户真实体验分享:坚持使用3个月的变化 - 博客万