Cygwin环境下fcntl的read()返回1而非实际读取字节数问题求助
问题根因与解决方案
你遇到的两个问题都是代码编写失误导致的,和read函数本身、Cygwin环境无关,修正方案如下:
1. read始终返回1的问题
这是运算符优先级错误导致的:
你写的while条件存在括号位置错误:
// 错误写法 while (((nRead = read(fd_in, buff, MAX_BUFFER_SIZE) > 0) && (rtnVal == TRUE)))
C语言中>比较运算符的优先级高于=赋值运算符,所以实际执行顺序是:
- 先调用
read得到实际读取字节数 - 判断这个返回值是否>0,得到布尔结果1(真)或0(假)
- 把这个布尔值赋值给
nRead
所以只要成功读到数据,nRead永远是1,和read的实际返回值无关。
修正方法:把赋值逻辑单独用括号包裹:
// 正确写法 while (((nRead = read(fd_in, buff, MAX_BUFFER_SIZE)) > 0) && (rtnVal == TRUE))
2. 16MB缓冲区触发段错误的问题
这是栈空间不足导致的:
你当前的缓冲区是函数内定义的局部数组char buff[MAX_BUFFER_SIZE],局部变量分配在进程栈空间,Cygwin默认栈大小仅为8MB左右,定义超过栈上限的局部数组会直接栈溢出触发段错误。
修正方案二选一即可:
- 把
buff的定义移到函数外,作为全局变量,全局变量分配在数据段,不受栈大小限制 - 改用
malloc动态分配缓冲区,使用完毕后释放,示例如下:
// 替换char buff[MAX_BUFFER_SIZE] char *buff = malloc(MAX_BUFFER_SIZE); if (buff == NULL) { // 内存分配失败处理 fprintf(stderr, "malloc buffer failed: %s\n", strerror(errno)); rtnVal = FALSE; } // 函数退出前释放 free(buff);
修正后完整可运行代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <sys/stat.h> #define BOOL char #define TRUE (1 < 2) #define FALSE (1 > 2) #define MAX_BUFFER_SIZE 15*1024*1024 // 15MB,符合你的性能要求 int copyfile(const char *in, const char *out) ; BOOL debug = TRUE ; int main(int argc, char *argv[]) { int rc = 0 ; char *in = "/e/DCIM/100MEDIA/DJI_0292.MP4" ; char *out = "/m/Videos/2021/2021-08-Other/temp/08140708_dji_0292.mp4" ; rc = copyfile(in, out) ; return rc ; } int copyfile(const char *in, const char *out) { int rtnVal = TRUE ; int fd_in = -1, fd_out = -1; char *buff = NULL, *out_ptr ; ssize_t nRead, nRemaining, nWritten, totWritten = 0 ; int save_errno ; struct stat st ; // 动态分配15MB缓冲区 buff = malloc(MAX_BUFFER_SIZE); if (buff == NULL) { fprintf(stderr, "Failed to alloc %d buffer: %s\n", MAX_BUFFER_SIZE, strerror(errno)); return FALSE; } unlink(out) ; // In case it exists ... if ((fd_in = open(in, O_RDONLY)) < 0) { fprintf(stderr, "Could not open input file %s\n\t%s\n", in, strerror(errno)) ; rtnVal = FALSE ; } else if ((fd_out = open(out, O_WRONLY | O_CREAT | O_EXCL, 0666)) < 0) { fprintf(stderr, "Could not open output file %s\n\t%s\n", out, strerror(errno)) ; rtnVal = FALSE ; } if (rtnVal) { if (stat(in, &st) < 0) { fprintf(stderr, "Could not stat input file: %s\n\t%s\n", in, strerror(errno)) ; rtnVal = FALSE; goto cleanup; } if (debug) fprintf(stdout, "\n\n\nSize of %s is %ld\n", in, st.st_size) ; // 修正括号位置 while (((nRead = read(fd_in, buff, MAX_BUFFER_SIZE)) > 0) && (rtnVal == TRUE)) { out_ptr = buff ; nRemaining = nRead ; while (nRemaining > 0) { nWritten = write(fd_out, out_ptr, nRemaining) ; if (nWritten >= 0) { out_ptr += nWritten ; totWritten += nWritten ; nRemaining -= nWritten ; if (debug) fprintf(stdout, "\tDEBUG: %ld bytes read. So far, %ld bytes have been written. %ld remain\n" , nRead, totWritten, nRemaining) ; } else if (errno != EINTR) { rtnVal = FALSE ; fprintf(stderr, "Could not copy from: %s\n" " to: %s\n" " %s\n" , in, out, strerror(errno) ) ; break ; } } // While remaining } // While read() } // If rtnVal cleanup: save_errno = errno ; if (fd_in >= 0) close(fd_in) ; if (fd_out >= 0) close(fd_out) ; if (buff != NULL) free(buff); if (rtnVal) { if (stat(out, &st) < 0) { fprintf(stderr, "Could not stat output file: %s\n\t%s\n", out, strerror(errno)) ; rtnVal = FALSE; } if (debug) fprintf(stdout, "Size of %s is %ld\n", out, st.st_size) ; } errno = save_errno ; return(rtnVal) ; }
修正后重新编译运行,read就会返回实际读取的字节数,15MB缓冲区也不会触发段错误,拷贝性能符合要求。
内容的提问来源于stack exchange,提问作者Dennis
相关产品推荐
相关产品推荐

