LINUX下写大文件 -D _FILE_OFFSET_BITS=64或者open时加O_LARGEFILE

本文探讨了在32位Linux系统下处理超过2GB的大文件时遇到的问题及解决方案,包括通过编译选项和使用特定标志来支持大文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://blog.163.com/xychenbaihu@yeah/blog/static/132229655201141211197621/

在32位机器下,默认情况下,文件长度是off_t类型,这个可以从ftrucate的参数,从stat获取的文件属性struct stat中都可以看出文件的长度是用off_t类型表示的,即文件的长度在32位机器下默认是long int类型。

       所以,默认情况下,在Linux系统下,fopen和open操作的文件大小不能超过2G

       我们制造了一个异常文件,5G左右,可以使用dd命令来构建,也可以写个脚本来构建。

       我写了一段程序来测试:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

int main(int argc,char *argv[])
{
 FILE *fp;
 int fd;

 fp = fopen("./bill_test","a+");                                                              //bill_test是一个5G左右的文件
 if(fp == NULL)
 {
  perror("fopen bill_test fail::");
 }
 else
 {
  int ret = 0;
  ret = fprintf(fp,"%s\t","bill"); 

  if(ret < 0)
  {
   perror("write bill_test fail::");
   fclose(fp);
   exit(1);
  }
  fclose(fp);
 }

 fd = open("./bill_test",O_APPEND|O_RDWR,0666);                  //bill_test是一个5G左右的文件
 if(fd == -1)
 {
  perror("open bill_test fail::");
 }
 else
 {
  int len=0;
  len = write(fd,"hello",5);
  if(len == -1)
  {
   perror("write bill_test fail::");
   close(fd);
   exit(1);
  }
  close(fd);
 }
 return 0;
}

//当使用: g++ file_test.cpp -o file_test           对源码编译后,运行结果如下:

./file_test
fopen bill_test fail::: File too large                      
open bill_test fail::: File too large

 

可以看出,在32位机器下,不能直接支持超过2G的文件。

 

解决方案一、

              g++   -D _FILE_OFFSET_BITS=64   file_test.cpp  -o   file_test

此时在用tail  -f    bill_test,然后再运行./file_test,可以看到数据被正常的写入bill_test文件中。

 

解决方案二、

             对与open,可以使用O_LARGEFILE参数,即:

             fd   =   open("./bill_test",O_LARGEFILE|O_APPEND|O_RDWR,0666);

             然后就没用问题了,但是fopen没有这个参数,只能按照方法一来解决。


#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/sendfile.h> #define PORT 8080 #define BUFFER_SIZE 4096 const char *get_content_type(const char *path) { const char *last_dot = strrchr(path, '.'); if (last_dot) { if (strcmp(last_dot, ".html") == 0) return "text/html"; if (strcmp(last_dot, ".txt") == 0) return "text/plain"; if (strcmp(last_dot, ".js") == 0) return "application/javascript"; if (strcmp(last_dot, ".css") == 0) return "text/css"; if (strcmp(last_dot, ".jpg") == 0) return "image/jpeg"; if (strcmp(last_dot, ".jpeg") == 0) return "image/jpeg"; if (strcmp(last_dot, ".png") == 0) return "image/png"; if (strcmp(last_dot, ".gif") == 0) return "image/gif"; if (strcmp(last_dot, ".ico") == 0) return "image/x-icon"; } return "application/octet-stream"; } // 发送HTTP响应 void send_response(int client_fd, int status, const char *status_msg, const char *content_type, const char *body, size_t body_len) { char header[BUFFER_SIZE]; // 构建响应头 int header_len = snprintf(header, sizeof(header), "HTTP/1.1 %d %s\r\n" "Content-Type: %s\r\n" "Content-Length: %zu\r\n" "Connection: close\r\n" "\r\n", status, status_msg, content_type, body_len); // 发送响应头 write(client_fd, header, header_len); // 发送响应体 if (body_len > 0) { write(client_fd, body, body_len); } } // 发送文件内容 void send_file(int client_fd, const char *file_path) { char buffer[BUFFER_SIZE]; int file_fd = open(file_path, O_RDONLY); if (file_fd < 0) { // 文件不存在 const char *not_found = "<html><body><h1>404 Not Found</h1></body></html>"; send_response(client_fd, 404, "Not Found", "text/html", not_found, strlen(not_found)); return; } // 获取文件大小 struct stat file_stat; fstat(file_fd, &file_stat); off_t file_size = file_stat.st_size; // 获取内容类型 const char *content_type = get_content_type(file_path); // 发送响应头 char header[BUFFER_SIZE]; int header_len = snprintf(header, sizeof(header), "HTTP/1.1 200 OK\r\n" "Content-Type: %s\r\n" "Content-Length: %ld\r\n" "Connection: close\r\n" "\r\n", content_type, file_size); write(client_fd, header, header_len); off_t offset = 0; ssize_t sentbytes; // fasong while(offset < file_size){ sentbytes = sendfile(client_fd,file_fd,&offset,file_size - offset); if(sentbytes <= 0){ perror("sendfile"); break; } offset += sentbytes; } close(file_fd); } int main() { int server_fd, client_fd; struct sockaddr_in server_addr, client_addr; socklen_t addr_len = sizeof(client_addr); char buffer[BUFFER_SIZE] = {0}; // 创建套接字 if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket failed"); exit(EXIT_FAILURE); } // 设置端口复用,避免重启地址被占用 int opt = 1; if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { perror("setsockopt"); exit(EXIT_FAILURE); } server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(PORT); // 绑定 if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("bind failed"); exit(EXIT_FAILURE); } // 监听 if (listen(server_fd, 10) < 0) { perror("listen"); exit(EXIT_FAILURE); } printf("Server listening on port %d\n", PORT); while (1) { // 接受连接 if ((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &addr_len)) < 0) { perror("accept"); continue; } // 读取请求 ssize_t bytes_read = read(client_fd, buffer, BUFFER_SIZE - 1); if (bytes_read < 0) { perror("read"); close(client_fd); continue; } buffer[bytes_read] = '\0'; // 解析请求行(第一行) char method[16], path[256]; sscanf(buffer, "%s %s", method, path); // 只处理GET请求 if (strcmp(method, "GET") != 0) { close(client_fd); continue; } // 如果请求根路径,则默认返回index.html if (strcmp(path, "/") == 0) { strcpy(path, "/index.html"); } // 去掉路径开头的'/',得到相对路径 char file_path[512]; snprintf(file_path, sizeof(file_path), ".%s", path); // 尝试打开文件 int file_fd = open(file_path, O_RDONLY); if (file_fd < 0) { // 文件不存在,返回404 const char *not_found_response = "HTTP/1.1 404 Not Found\r\n" "Content-Type: text/html\r\n" "Connection: close\r\n" "\r\n" "<html><body><h1>404 Not Found</h1></body></html>"; write(client_fd, not_found_response, strlen(not_found_response)); close(client_fd); continue; } // 获取文件信息(主要是文件大小) struct stat file_stat; fstat(file_fd, &file_stat); off_t file_size = file_stat.st_size; // 获取内容类型 const char *content_type = get_content_type(file_path); // 构建响应头 char header[BUFFER_SIZE]; int header_len = snprintf(header, sizeof(header), "HTTP/1.1 200 OK\r\n" "Content-Type: %s\r\n" "Content-Length: %ld\r\n" "Connection: close\r\n" "\r\n", content_type, file_size); // 发送响应头 write(client_fd, header, header_len); // 发送文件内容 ssize_t bytes_sent; while ((bytes_sent = send_file(client_fd, file_path) > 0) { // 使用sendfile高效发送文件 } // 关闭文件和客户端连接 close(file_fd); close(client_fd); } close(server_fd); return 0; }检查这段代码的错误
最新发布
08-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值