You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何仅读取必要字节,从流式媒体中提取日期时间元数据?

从流式媒体中读取日期元数据(无需加载完整文件)

针对你的场景,metadata-extractor 本身支持从 InputStream 读取元数据,且多数图片/视频的日期元数据位于文件头部,无需加载完整媒体。关键是要处理流的复用,确保读取元数据后,后续生成缩略图的流程仍能正常读取完整流。

实现方案

  • 将管道输入流包装为可标记/重置的缓冲流,让元数据读取完成后能回退到流的起始位置。
  • 使用 metadata-extractor 从缓冲流中读取元数据,它会自动在获取到足够信息后停止读取。
  • 重置缓冲流,供后续缩略图生成流程使用。

修改后的代码示例

import com.drew.imaging.ImageMetadataReader;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifSubIFDDirectory;
import com.drew.metadata.mp4.Mp4Directory;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

public class MediaProcessor {
    private static final Logger LOGGER = Logger.getLogger(MediaProcessor.class.getName());
    // 设置足够大的标记大小,适配多数媒体的头部元数据(1MB足够覆盖绝大多数场景)
    private static final int MARK_LIMIT = 1024 * 1024;

    public static void createThumbnailImage(Media media, TmpMedia tmpMedia) throws IOException {
        PipedInputStream mediaIn = new PipedInputStream();
        PipedOutputStream mediaOut = new PipedOutputStream(mediaIn);
        
        // 启动线程读取媒体到管道输出流
        new Thread(() -> {
            try {
                App.storage.getMedia(media, mediaOut);
            } catch (IOException e) {
                LOGGER.log(Level.WARNING, "Error getting Media for thumbnail", e);
            } finally {
                try {
                    mediaOut.close();
                } catch (IOException e) {
                    LOGGER.log(Level.SEVERE, "Failed to close media output stream", e);
                }
            }
        }).start();

        // 包装为可标记的缓冲流
        BufferedInputStream bufferedMediaIn = new BufferedInputStream(mediaIn, MARK_LIMIT);
        bufferedMediaIn.mark(MARK_LIMIT);

        // 读取日期元数据
        Date mediaDateTime = null;
        try {
            Metadata metadata = ImageMetadataReader.readMetadata(bufferedMediaIn);
            // 读取图片EXIF原始日期
            ExifSubIFDDirectory exifDir = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
            if (exifDir != null) {
                mediaDateTime = exifDir.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL);
            }
            // 读取MP4视频创建时间(按需添加其他格式支持)
            if (mediaDateTime == null) {
                Mp4Directory mp4Dir = metadata.getFirstDirectoryOfType(Mp4Directory.class);
                if (mp4Dir != null) {
                    mediaDateTime = mp4Dir.getDate(Mp4Directory.TAG_CREATION_TIME);
                }
            }
        } catch (Exception e) {
            LOGGER.log(Level.WARNING, "Failed to read media metadata", e);
        } finally {
            // 重置流到起始位置,供后续缩略图生成使用
            try {
                bufferedMediaIn.reset();
            } catch (IOException e) {
                LOGGER.log(Level.SEVERE, "Failed to reset media stream", e);
                throw e;
            }
        }

        // 业务逻辑处理日期(示例)
        if (mediaDateTime != null) {
            LOGGER.info("Media date time: " + mediaDateTime);
        }

        // 后续缩略图生成逻辑,使用bufferedMediaIn代替原mediaIn
        // Rest of code...
        // Example: ImageIO.read(bufferedMediaIn);
    }
}

关键注意事项

  • 标记大小设置:MARK_LIMIT 需足够容纳媒体头部的元数据,1MB对绝大多数图片和视频都足够;如果遇到元数据在文件尾部的格式(如少数MP4文件),这种方式可能无法读取,此时需结合业务场景评估是否需要特殊处理。
  • 流的关闭:必须确保管道输出流在读取完成后关闭,避免资源泄漏。
  • 多格式扩展:metadata-extractor 支持几十种媒体格式,可根据业务中涉及的媒体类型,添加对应元数据目录的读取逻辑。

内容的提问来源于stack exchange,提问作者Hein Gertenbach

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 14:13:20