ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Daft 文件类型 API 详解:daft.file.File 与 ImageFile / AudioFile / VideoFile / Hdf5File 多模态文件处理

Daft 文件类型 API 详解:daft.file.File 与 ImageFile / AudioFile / VideoFile / Hdf5File 多模态文件处理 Daft 文件类型 API 详解daft.file.File 与 ImageFile / AudioFile / VideoFile / Hdf5File 多模态文件处理【免费下载链接】DaftHigh-performance data engine for AI and multimodal workloads. Process images, audio, video, and structured data at any scale项目地址: https://gitcode.com/GitHub_Trending/da/Daft本文系统讲解 Daft 中FileDataType 及其配套的文件类体系daft.file.File作为基类提供跨本地与远程存储的统一文件读写接口ImageFile、AudioFile、VideoFile、Hdf5File四个子类则分别针对图片、音频、视频与 HDF5 数据提供领域化操作。读完本文你可以掌握文件引用在 DataFrame 表达式中的构造方式、open()/size()/mime_type()/to_tempfile()等核心方法的用法、各子类元数据提取与解码 API 的参数细节以及缓冲区大小buffer_size背后的性能设计。一、File 类型体系总览FileDataType 为 Daft 提供了一等公民式的文件数据支持使得文件操作可以在分布式环境中无缝进行——文件引用本身是一个轻量级的URL IO 配置结构真正的字节流读取被延迟到open()时才发生且底层支持 S3、GCS 等远程对象存储。从 daft/file/init.py 可以看到该模块导出的公共 API 为__all__ [AudioFile, DaftFileIO, File, Hdf5File, ImageFile, VideoFile, open_file]类继承关系为File是抽象基类ImageFile、AudioFile、VideoFile、Hdf5File均继承自File。每个子类的构造器都会把MediaType固定为对应模态如MediaType.image()并在文件头嗅探magic bytes结果与声明模态不符时抛出ValueError见 daft/file/image.py。文件类内部持有 Rust 侧的PyFileReference对象见 daft/file/file.py它封装了一个五元组self._inner PyFileReference._from_tuple( (media_type._media_type, url, io_config, position, size) )这五个字段决定了文件引用的全部语义。对应到 Python 构造函数File( url: str, # 完整路径或 URL如 s3://bucket/path/to/data.csv io_config: IOConfig | None None, # 对象存储认证/代理等 IO 配置 media_type: MediaType MediaType.unknown(), # 声明的媒体类型 position: int | None None, # 范围读取的起始字节位置None 表示整文件读取 size: int | None None, # 范围读取的窗口大小None 表示整文件读取 )需要注意源码中有两处弃用提示构造参数offset/length已被position/size取代传旧参数会触发DeprecationWarning并自动映射见 daft/file/file.py#L59-L87。属性File.offset与File.length同样处于弃用状态应使用File.position和File.size()。MediaType定义于 daft/datatype.py提供unknown()、video()、audio()、image()、hdf5()五个工厂方法DataType.file(media_type)则可据此构造出File[Image]、File[Video]等带模态标注的 DataType见 daft/datatype.py#L867-L869。缓冲区大小约定File体系中三个默认缓冲区常量daft/file/file.py#L13-L15贯穿所有读写路径理解它们是理解性能行为的关键常量大小用途BUFFER_SNIFF4 KBMIME 类型嗅探mime_type()只读取文件头BUFFER_METADATA64 KB元数据提取metadata()只读容器头BUFFER_COPY1 MB全量读取/拷贝to_tempfile()、解码等Hdf5File额外定义了HDF5_SCAN_BUFFER_SIZE 1024元数据扫描与HDF5_DEFAULT_BUFFER_SIZE 64 KB打开文件。其类文档解释了原因h5py 在遍历元数据与 chunk 索引时会执行大量 seek 后的小读因此默认使用比通用File更小的文件缓冲区见 daft/file/hdf5.py#L30-L38。二、基类 File 的核心方法以下方法定义在 daft/file/file.py 中全部子类继承。File对象实现标准 Python 文件协议readable()返回 True、writable()返回 False、seekable()返回 True因此可以直接传给多数接受 file-like 对象的第三方库。当前实现中文件是只读的。属性与探测方法方法/属性返回值说明pathstr完整路径或 URLnamestr从路径/URL 提取的文件名basenamepositionint \| None范围读取的起始字节位置size()int文件字节大小以BUFFER_SNIFF打开后向底层查询exists()bool文件是否存在于其路径/URL 上mime_type()str通过 magic bytes 嗅探 MIME 类型无法识别时回退为application/octet-streammime_type()的实现细节值得注意daft/file/file.py#L176-L189先以 4 KB 缓冲打开文件调用guess_mime_type()做 magic bytes 检测若文件不存在FileNotFoundError则对.h5/.hdf5后缀硬编码返回application/vnd.hdfgroup.hdf5否则回退到 Python 标准库mimetypes.guess_type()按扩展名猜测。在此基础上提供四个模态判断方法f.is_video() # MIME 以 video/ 开头 f.is_audio() # MIME 以 audio/ 开头 f.is_image() # MIME 以 image/ 开头 f.is_hdf5() # MIME application/vnd.hdfgroup.hdf5以及对应的类型转换方法as_video()/as_audio()/as_image()/as_hdf5()。它们的实现模式一致以as_image()为例daft/file/file.py#L276-L291检查对应可选依赖pillow / soundfile / av / h5py是否可用缺失时抛出带有pip install daft[image]等提示的ImportError通过is_xxx()校验 MIME模态不符则抛出ValueError用__new__创建子类实例并直接复用同一个_inner引用——即不产生新的 IO 配置或网络请求只是把同一文件引用升格为子类。open() 与 to_tempfile()def open(self, buffer_size: int | None None) - PyDaftFile: if self.position is None and self._inner.size() is None and not self.exists(): raise FileNotFoundError(fFile {self.path} does not exist) return PyDaftFile._from_file_reference(self._inner, buffer_sizebuffer_size)open()返回 Rust 侧的PyDaftFile支持标准read/seek/tell接口并额外提供size()、guess_mime_type()、_supports_range_requests()等方法。对于声明了范围position非空的引用open()不会做存在性检查因为范围引用语义上允许按窗口读取。to_tempfile(buffer_sizeBUFFER_COPY)将远端文件完整落盘为本地临时文件前缀daft_供那些无法接受 file-like 对象、只接受本地路径的库使用。其实现daft/file/file.py#L191-L217有两个要点若文件不支持 range requests 或小于 1 KB直接整体read()一次否则用shutil.copyfileobj以buffer_size默认 1 MB分块流式拷贝这是一个消费性方法内部会关闭原始文件对象调用后原File引用不能再继续使用。基类使用示例基类文档自带的最小示例daft/file/file.py#L37-L48展示了文件引用 UDF的典型组合import daft from daft.functions import file df daft.from_pydict({paths: [data.json]}) df df.select(file(df[paths])) daft.func def read_json(file: daft.File) - str: import json with file.open() as f: data json.load(f) return data[text]三、在 DataFrame 表达式中构造文件引用文件类型并非只能在 UDF 里手工构造。daft/functions/file_.py 提供了一组表达式级函数可作用于任意 String 列把路径字符串列转换为文件引用列函数返回类型说明file(url, io_configNone)File通用文件引用image_file(url, verifyFalse, io_configNone)File[Image]图片文件引用audio_file(url, verifyFalse, io_configNone)File[Audio]音频文件引用video_file(url, verifyFalse, io_configNone)File[Video]视频文件引用hdf5_file(url, verifyFalse, io_configNone)File[Hdf5]HDF5 文件引用file_path(file)String提取文件路径URLfile_size(file)UInt64文件字节大小file_exists(file)Boolean文件是否存在guess_mime_type(bytes_expr)String对二进制列做 magic bytes MIME 检测无法识别返回 None其中verify参数的语义见各函数 docstring若为True会校验文件存在且 MIME 类型与声明模态一致任何一个文件不符都会使整个作业报错默认False时不做逐文件校验模态错误会在后续metadata()/解码时才会暴露。这是一个在作业尽早失败fail fast与避免对海量路径逐个发起 HEAD 请求之间的权衡开关。guess_mime_type()支持的格式包括 PNG、JPEG、GIF、WEBP、PDF、ZIP、MP3、WAV、OGG、MP4、MPEG、HDF5 与 HTML见 daft/functions/file_.py#L134-L169。四、ImageFile图片元数据与解码ImageFile定义于 daft/file/image.py依赖 Pillow缺失时提示pip install daft[image]。构造时即做模态校验super().__init__(url, io_config, MediaType.image())后调用self.is_image()不是图片直接抛ValueError。两个核心方法def metadata(self) - ImageMetadata: with self.open(buffer_sizeBUFFER_METADATA) as f: img pil_image.open(f) return ImageMetadata(widthimg.width, heightimg.height, formatimg.format, modeimg.mode) def decode(self, mode: str | None None, buffer_size: int | None BUFFER_COPY) - pil_image.Image: with self.open(buffer_sizebuffer_size) as f: img pil_image.open(f) img.load() if mode is not None and img.mode ! mode: img img.convert(mode) return imgmetadata()利用 PIL 的惰性打开特性——Image.open()只读文件头即得到宽高、格式与颜色模式不触碰像素数据因此只需 64 KB 缓冲区适合对大规模图片列做零解码元数据扫描decode(mode...)在可选参数mode与当前模式不一致时自动convert(mode)mode可取RGB、RGBA、L等 PIL 模式串buffer_size默认 1 MB。ImageMetadata是一个 TypedDict字段为width、height、format、mode均可空见 daft/file/typing.py#L37-L41。五、AudioFile音频元数据、NumPy 转换与重采样AudioFile定义于 daft/file/audio.py依赖soundfiledaft[audio]扩展。三个方法def metadata(self) - AudioMetadata: # 返回 sample_rate、channels、frames、format、subtype with self.open(buffer_sizeBUFFER_METADATA) as f, sf.SoundFile(f) as af: return AudioMetadata(sample_rateaf.samplerate, channelsaf.channels, framesaf.frames, formataf.format, subtypeaf.subtype) def to_numpy(self, buffer_size: int BUFFER_COPY) - np.ndarray[Any, np.dtype[np.float64]]: # 先落盘到临时文件再用 soundfile 读取 with self.to_tempfile(buffer_size) as tmp: audio, _ sf.read(tmp) return audio def resample(self, sample_rate: int, buffer_size: int BUFFER_COPY) - np.ndarray: # 依赖 librosa采样率已一致时直接返回原始数据 with self.to_tempfile(buffer_size) as f: data, samplerate sf.read(f) if samplerate ! sample_rate: return librosa.resample(data, orig_srsamplerate, target_srsample_rate) return data值得注意的实现细节to_numpy()与resample()都先走to_tempfile()落盘再交给soundfile这是因为 soundfile 对 file-like 对象的 seek 支持有限落盘路径更通用resample()额外要求librosa可用缺失时提示pip install daft[audio]。AudioMetadata字段见 daft/file/typing.py#L29-L34。六、VideoFile元数据、帧迭代与按索引取帧VideoFile定义于 daft/file/video.py依赖avPyAV与 Pillowdaft[video]扩展。它是五个类中 API 最丰富的一个。metadata()def metadata(self, buffer_size: int BUFFER_METADATA) - VideoMetadata:返回VideoMetadatawidth、height、fps、duration、frame_count、time_base均可空。实现上有多级回退daft/file/video.py#L45-L103fps优先stream.average_rate缺失时用guessed_rateduration优先容器级container.duration微秒换算为秒缺失时用stream.duration × time_basetime_base再缺失时回退1e-6frame_count优先stream.frames若无效且 duration/fps 可得则用round(duration * fps)估算否则为None。frames()惰性帧迭代器def frames(self, start_time: float 0, end_time: float | None None, width: int | None None, height: int | None None, is_key_frame: bool | None None, sample_interval_seconds: float | None None, buffer_size: int BUFFER_COPY, ) - Iterator[VideoFrameData]:其 docstring 明确说明该接口与daft.read_video_frames()的逐帧 schema 对齐。关键行为实现见 daft/file/video.py#L171-L288范围裁剪start_time 0时先container.seek()到目标时间戳seek 可能落在稍早位置之后逐帧跳过frame.time start_time的帧end_time到达即停止关键帧过滤is_key_frameTrue时会设置codec_context.skip_frame NONKEY让解码器层面直接跳过非关键帧而非解码后再丢弃时间间隔采样sample_interval_seconds采用取时间戳 ≥ 下一个目标时刻的首帧算法目标序列为start_time, start_time interval, ...并带 1e-9 级 epsilon 吸收浮点漂移对 VFR可变帧率视频会一次性推进多个已被跨过目标避免积压缩放width/height必须同时提供否则抛ValueError通过frame.reformat(width..., height...)在解码后立即缩放帧索引当frame.pts、time_base、fps均可得时用(pts - start_pts) × time_base × fps反算真实帧序号而非顺序计数。每个 yield 的VideoFrameData是 TypedDictdaft/file/typing.py#L18-L26键为frame_index、frame_time、frame_time_base、frame_pts、frame_dts、frame_duration、is_key_frame、dataPIL Image。此外keyframes(start_time0, end_timeNone)是frames(is_key_frameTrue)的语法糖。源码中还嵌入了可观测性设计当文件级 tracing 开启时_PyFileTracingSpan.is_enabled()open/seek/decode/to_image 各阶段分别包裹video_open()、video_seek()、video_decode()、video_to_image()span且生成器在挂起期间不会持有已开启的 span见 daft/file/video.py#L151-L169。get_frame_by_idx()def get_frame_by_idx(self, idx: int, buffer_size: int BUFFER_COPY) - PIL.Image.Image:按帧序号随机取单帧先用idx / fps估算目标时间container.seek(..., backwardTrue)定位到不晚于目标的最近关键帧再顺序解码直至帧序号匹配越界抛IndexError。七、Hdf5File面向 DataFrame 的 HDF5 访问Hdf5File定义于 daft/file/hdf5.py依赖h5py与numpydaft[hdf5]扩展。类文档的核心设计说明是它保留File.open()作为原始字节流 API再叠加一组模仿 h5pyFile/Group常用操作的辅助方法并把返回值统一收敛为 DataFrame 友好的类型如list[str]而非 h5py 的 view 对象。方法说明open(buffer_sizeNone)覆盖基类默认值为HDF5_DEFAULT_BUFFER_SIZE64 KBmetadata(group/)递归遍历 group 下的 dataset/group返回Hdf5ObjectMetadata列表keys(group/)返回直接子成员名list[str]attrs(h5path/)返回对象属性字典visit(funcNone, *, group/)双形态重载带 visitor 回调或返回全部名称列表read(dataset)单个路径返回np.ndarray序列路径返回{path: array}字典且复用同一次文件打开metadata()返回的Hdf5ObjectMetadata键为h5path、kinddataset或group、shape、dtype、chunks、compression见 daft/file/typing.py#L44-L50结构上就是为df.from_pydict(hdf5.metadata())这类先扫描元数据、再按 path 选择性读数据集的两阶段模式设计的。所有元数据扫描方法keys/attrs/visit/metadata统一使用 1 KB 的HDF5_SCAN_BUFFER_SIZE而read()使用 64 KB 默认缓冲这个差异正对应了h5py 遍历元数据时频繁小读的 IO 特征。另外read()显式拒绝 Mapping 参数别名映射并规定请求路径解析到 group 而非 dataset 时抛TypeError。八、工程实践建议与测试验证结合源码实际使用时有几点建议模态校验时机批量处理混合模态文件时优先在表达式层用image_file(url, verifyTrue)等函数尽早暴露脏数据而不是在 UDF 内逐个 try/except元数据与解码分离对大规模数据集先用metadata()4KB64KB 级别的头读取产出统计列再只对目标子集调用decode()/frames()/to_numpy()避免全量解码只读语义File当前实现writable()恒为 False写入需求应走 Daft 的 writer/sink 路径依赖安装各子类的可选依赖互不强制——图片需要daft[image]Pillow音频需要daft[audio]soundfile/librosa视频需要daft[video]av PillowHDF5 需要daft[hdf5]h5py numpy。相关行为在仓库的 tests/file/ 测试目录中有对应测试覆盖表达式侧函数file、image_file等的参数定义可对照 daft/functions/file_.py。官方 API 参考页为 docs/api/datatypes/file_types.md本页以 mkdocstrings 方式自动生成daft.file.File、ImageFile、AudioFile、VideoFile、Hdf5File五个类的公开方法文档。【免费下载链接】DaftHigh-performance data engine for AI and multimodal workloads. Process images, audio, video, and structured data at any scale项目地址: https://gitcode.com/GitHub_Trending/da/Daft创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表