我正在读取文件格式(TIFF),它从文件开头有32位无符号偏移量。
不幸的是,fseek的原型,我通常会采用特定的文件偏移方式,是:
int fseek ( FILE * stream, long int offset, int origin );
所以偏移是签名的。我该如何处理这种情况?我应该使用不同的功能进行搜索吗?
答案 0 :(得分:0)
您可以尝试使用lseek64()
(man page)
#define _LARGEFILE64_SOURCE /* See feature_test_macros(7) */
#include <sys/types.h>
#include <unistd.h>
off64_t lseek64(int fd, off64_t offset, int whence);
使用
int fd = fileno (stream);
来自The GNU C lib - Setting the File Position of a Descriptor
的备注此功能类似于lseek功能。不同之处在于offset参数的类型为off64_t而不是off_t,这使得32位机器可以处理大于2 ^ 31字节且最多2 ^ 63字节的文件。必须使用open64打开文件描述符filedes,否则off64_t可能导致的大偏移将导致在小文件模式下使用描述符出错。
当在32位机器上使用_FILE_OFFSET_BITS == 64编译源文件时,此函数实际上以名称lseek提供,因此透明地替换了32位接口。
关于fd
和stream
,来自Streams and File Descriptors
由于流是根据文件描述符实现的,因此您可以从流中提取文件描述符,并直接在文件描述符上执行低级操作。您最初也可以将连接作为文件描述符打开,然后创建与该文件描述符关联的流。
答案 1 :(得分:0)
在更深入地研究这个问题并考虑其他评论和答案(谢谢)之后,我认为最简单的方法是在偏移量大于2147483647字节时进行两次搜索。这允许我将偏移保持为uint32_t
并继续使用fseek
。因此定位代码如下:
// note: error handling code omitted
uint32_t offset = ... (whatever it is)
if( offset > 2147483647 ){
fseek( file, 2147483647, SEEK_SET );
fseek( file, (long int)( offset - 2147483647 ), SEEK_CUR );
} else {
fseek( file, (long int) offset, SEEK_SET );
}
使用64位类型的问题是代码可能在32位架构上运行(除其他外)。有一个函数fsetpos
使用结构fpos_t
来管理任意大的偏移,但这会带来一系列复杂性。虽然fsetpos
可能有意义,如果我真的使用任意大尺寸的偏移,因为我知道最大可能的偏移是uint32_t,那么双重搜索满足了这种需要。
请注意,此解决方案允许在32位系统上处理所有TIFF文件。如果您考虑像PixInsight这样的商业程序,这一点很明显。在32位系统上运行时,PixInsight只能处理小于2147483648字节的TIFF文件。要处理完整大小的TIFF文件,用户必须在64位计算机上使用64位版本的PixInsight。这可能是因为PixInsight程序员使用64位类型在内部处理偏移。由于我的解决方案只使用32位类型,我可以在32位系统上处理完整大小的TIFF文件(只要底层操作系统可以处理大文件)。