unix环境编程试题
问题1
请设计一个文件处理系统,要求能同时处理以下两种任务:
- 将大型日志文件(如10GB的服务器日志)复制到备份目录
- 同时需要逐行分析日志内容,提取其中的错误信息(包含"ERROR"的行)
要求:
- 考虑性能优化
- 考虑内存使用
- 你会选择哪种I/O操作方式,并解释原因
- 描述具体的实现思路
- 如果同时使用系统调用I/O和标准库I/O处理同一个文件,可能会遇到什么问题?
- 如何处理文件读写过程中的错误?
- 在不同操作系统上,这个程序可能会遇到什么兼容性问题?
答案
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>#define COPY_BUFFER_SIZE (1024*1024) // 1MBvoid process_log_file(const char *source, const char *dest) {// 第一步:使用低级I/O复制文件int fd_source = open(source, O_RDONLY);int fd_dest = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0644);char buffer[COPY_BUFFER_SIZE];// 先完整复制文件while (1) {ssize_t bytes_read = read(fd_source, buffer, COPY_BUFFER_SIZE);if (bytes_read <= 0) break;write(fd_dest, buffer, bytes_read);}close(fd_source);close(fd_dest);// 第二步:使用标准I/O分析文件FILE *fp_source = fopen(source, "r");FILE *fp_error = fopen("error.log", "w");char line[4096];while (fgets(line, sizeof(line), fp_source)) {if (strstr(line, "ERROR")) {fputs(line, fp_error);}}fclose(fp_source);fclose(fp_error);
}
用内存映射:
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>void process_log_file(const char *source, const char *dest) {int fd_source = open(source, O_RDONLY);int fd_dest = open(dest, O_RDWR | O_CREAT | O_TRUNC, 0644);FILE *fp_error = fopen("error.log", "w");// 获取文件大小struct stat sb;fstat(fd_source, &sb);off_t file_size = sb.st_size;// 扩展目标文件大小ftruncate(fd_dest, file_size);// 映射源文件和目标文件到内存char *src_ptr = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd_source, 0);char *dest_ptr = mmap(NULL, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_dest, 0);// 直接内存复制memcpy(dest_ptr, src_ptr, file_size);// 分析文件内容char *current = src_ptr;char *end = src_ptr + file_size;char line[4096];size_t pos = 0;while (current < end) {if (*current == '\n' || current == end - 1) {line[pos] = '\0';if (strstr(line, "ERROR")) {fprintf(fp_error, "%s\n", line);}pos = 0;} else {line[pos++] = *current;}current++;}// 清理资源munmap(src_ptr, file_size);munmap(dest_ptr, file_size);close(fd_source);close(fd_dest);fclose(fp_error);
}