如何在Kotlin/Java中获取网络链接音频文件时长?解决UnsupportedAudioFileException异常
解决Java/Kotlin中AudioSystem不支持MP3/MP4格式的问题
哈哈,这个坑我踩过!你遇到的UnsupportedAudioFileException根本不是MP3/MP4格式的问题——而是Java标准库的AudioSystem天生就不支持这些受专利保护的音频格式。
为什么会报错?
JDK自带的音频API只原生支持WAV、AU、AIFF这类无专利的开源格式。MP3和MP4因为历史上的专利授权限制,Oracle并没有将它们的解码器打包进JDK标准库,所以直接调用AudioSystem.getAudioInputStream()处理MP3/MP4时,必然会抛出格式不支持的异常。
解决方案
下面给你几种实用的解决思路,根据你的项目需求选择即可:
方案1:用JLayer处理MP3(轻量专用)
JLayer是一个成熟的开源MP3解码库,专门针对MP3格式,依赖小、用法简单。
首先添加依赖(以Maven为例):
<dependency> <groupId>javazoom</groupId> <artifactId>jlayer</artifactId> <version>1.0.1</version> </dependency>
然后用Kotlin代码获取MP3时长:
import javazoom.jl.player.advanced.AdvancedPlayer import javazoom.jl.player.advanced.PlaybackEvent import javazoom.jl.player.advanced.PlaybackListener import java.net.URL fun getMp3Duration(url: String): Double { var durationSeconds = 0.0 val urlObj = URL(url) // 初始化播放器,仅用于获取元数据 val player = AdvancedPlayer(urlObj.openStream()) player.setPlayBackListener(object : PlaybackListener() { override fun playbackStarted(event: PlaybackEvent?) { event?.source?.player?.let { durationSeconds = it.mpegAudioDecoder.streamLengthInSeconds.toDouble() } } }) // 播放1帧即可触发元数据加载,不需要完整播放 try { player.play(0, 1) } catch (e: Exception) { // 捕获播放1帧时的正常终止异常 } finally { player.close() } return durationSeconds } // 使用示例 fun main() { val url = "https://cdn.bandithemepark.net/lindburgh/HyperionHal.mp3" val duration = getMp3Duration(url) val lengthTicks = duration * 20 println("时长(秒):$duration,Ticks:$lengthTicks") }
方案2:用JavaFX Media API支持多格式(MP3/MP4通用)
如果你的项目可以引入JavaFX模块,那Media API是更优选择——它原生支持MP3、MP4、WAV等多种常见音频格式,获取时长的代码更简洁。
注意:JDK 11及以上版本中JavaFX是单独模块,需要单独添加依赖(以Maven为例):
<dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-media</artifactId> <version>21.0.1</version> <classifier>linux</classifier> <!-- 根据你的系统替换:win/mac --> </dependency>
对应的Kotlin代码:
import javafx.scene.media.Media import javafx.scene.media.MediaPlayer import java.net.URL fun getAudioDuration(url: String): Double { val mediaUrl = URL(url).toExternalForm() val media = Media(mediaUrl) // 等待元数据加载完成(JavaFX媒体对象是异步加载的) val duration = if (media.duration.isUnknown) { // 同步等待加载完成,实际项目中建议用异步回调 Thread.sleep(1000) media.duration.toSeconds() } else { media.duration.toSeconds() } // 释放资源 MediaPlayer(media).dispose() return duration }
方案3:用Apache Tika解析通用音频元数据
如果你需要处理多种音频格式(不止MP3/MP4),Apache Tika可以解析几乎所有常见媒体文件的元数据,包括时长。不过它的依赖相对较重,适合需要全面格式支持的场景。
添加Maven依赖:
<dependency> <groupId>org.apache.tika</groupId> <artifactId>tika-core</artifactId> <version>2.9.1</version> </dependency> <dependency> <groupId>org.apache.tika</groupId> <artifactId>tika-parsers-standard-package</artifactId> <version>2.9.1</version> </dependency>
Kotlin代码示例:
import org.apache.tika.metadata.Metadata import org.apache.tika.parser.ParseContext import org.apache.tika.parser.audio.AudioParser import java.io.InputStream import java.net.URL fun getAudioDurationWithTika(url: String): Double { val metadata = Metadata() val inputStream: InputStream = URL(url).openStream() try { val parser = AudioParser() parser.parse(inputStream, null, metadata, ParseContext()) // 从元数据中获取时长(单位:秒) val durationStr = metadata.get("xmpDM:duration") return durationStr?.toDouble() ?: 0.0 } finally { inputStream.close() } }
注意事项
- 所有方案都要处理网络异常(比如链接失效、超时)和文件损坏的情况,记得添加try-catch块。
- 如果是Android项目,建议使用Android自带的
MediaMetadataRetriever类,比上面的方案更适配移动端。
内容的提问来源于stack exchange,提问作者PartyPlanet
相关产品推荐
相关产品推荐

