Java中如何判断一个文件是否为MP3文件

这两天在做一个项目,在线音乐播放器。在设计上传音乐模块的时候,我想到有以下几点问题:

1. 用户是否已经登录?

2. 音乐是否已经上传过?

3. 文件是否真的是mp3文件?

而在这三个问题当中最不好解决的就是第三个问题。我花了将近一天的时间,去查找资料、博客,但经过尝试,发现都没有一个准确的答案。

最后我发现一个问题,就是在上传非MP3文件的时候,它总是会抛异常,于是我就在想,把异常 catch 住,然后在 catch 的时候,同时返回错误信息,在经过多次尝试后发现真的可以。

首先你需要引入一个依赖

<!-- https://mvnrepository.com/artifact/net.jthink/jaudiotagger 判断文件是否是音乐 -->
        <dependency>
            <groupId>net.jthink</groupId>
            <artifactId>jaudiotagger</artifactId>
            <version>2.2.6-PATHRIK</version>
        </dependency>

这是部分源码:

@RestController
@RequestMapping("/music")
public class MusicController {

    @Value("${music.local.path}")
    private String SAVE_PATH;

    @Autowired
    private MusicMapper musicMapper;

    @RequestMapping("/upload")
    public Result<Boolean> uploadMusic(String singer, MultipartFile file, HttpServletRequest request) throws ReadOnlyFileException, CannotReadException, TagException, InvalidAudioFrameException {
     
        // 获取文件的名字  xxx.mp3
        String fileName = file.getOriginalFilename();
        System.out.println("fileName:" + fileName);

        // 整个路径
        String path = SAVE_PATH + fileName;
        System.out.println("path:" + path);

        File dest = new File(path);
        if(!dest.exists()) {
            dest.mkdirs();
        }
        // 上传文件到目标路径
        try {
            file.transferTo(dest);
            // 判断上传的文件是否为音乐
            MP3File mp3File = (MP3File) AudioFileIO.read(dest);
            if(!mp3File.hasID3v1Tag() || !mp3File.hasID3v2Tag()) {
                dest.delete();
                return new Result<>(-1, "请上传音乐文件", false);
            }
        } catch (IOException e) {
            if(dest != null) {
                dest.delete();
            }
            e.printStackTrace();
            return new Result<>(-1, "上传文件失败", false);
        }
    }
}

这是最开始的写法,当我用 postman 测试时,发现上传非MP3文件,它会抛异常,异常信息会返回到 postman 上。

上传的文件是一个 txt 文件,只不过我把后缀名改成了 MP3,可以看到,异常信息被返回到了 客户端。

这是部分异常信息:

{

    "timestamp": "2025-03-24T01:30:18.835+00:00",

    "status": 500,

    "error": "Internal Server Error",

    "trace": "org.jaudiotagger.audio.exceptions.InvalidAudioFrameException: No audio header found within 错题本 - 副本.mp3\r\n\tat 

    "message": "No audio header found within 错题本 - 副本.mp3",

    "path": "/music/upload"

}

可以看到抛出了 InvalidAudioFrameException 的异常:No audio header found within 错题本 - 副本.mp3(在 错题本 - 副本.mp3 中没有找到音频头),说明文件并不是一个MP3文件

那么当我上传的文件不是 MP3文件(后缀也不是mp3) 时呢,比如说 txt文件

 可以看到抛出了 CannotReadException 的异常:No Reader associated with this extension:txt(没有Reader与此扩展相关联:txt),大概意思是说无法读取这个文件因为这是 txt 文件,由此也可看出文件不是MP3文件

可见这样写是完全可以的,但是把异常信息写回到客户端很不雅观,于是我就 catch 了一下,并且返回了一些错误信息。

这里采用的是先上传再判断的方式。也就是说不管文件是什么类型,先上传,如果 catch 到异常了

再把上传过的文件删除掉即可。

具体实现方式看代码:

@RestController
@RequestMapping("/music")
public class MusicController {

    @Value("${music.local.path}")
    private String SAVE_PATH;

    @Autowired
    private MusicMapper musicMapper;

    @RequestMapping("/upload")
    public Result<Boolean> uploadMusic(String singer, MultipartFile file, HttpServletRequest request) throws ReadOnlyFileException {

        // 获取文件的名字  xxx.mp3
        String fileName = file.getOriginalFilename();
        System.out.println("fileName:" + fileName);

        // 整个路径
        String path = SAVE_PATH + fileName;
        System.out.println("path:" + path);

        File dest = new File(path);
        if(!dest.exists()) {
            dest.mkdirs();
        }
        // 上传文件到目标路径
        try {
            file.transferTo(dest);
            // 判断上传的文件是否为音乐
            MP3File mp3File = (MP3File) AudioFileIO.read(dest);
            // 这个 if 语句其实没什么用,本来是想通过 if 语句来判断到底是不是mp3文件
            // 但是后来发现它会抛异常,根本执行不到这里,所有就不用这种方式了
//          if(!mp3File.hasID3v1Tag() || !mp3File.hasID3v2Tag()) {
//              dest.delete();
//              return new Result<>(-1, "请上传音乐文件", false);
            }
        } catch (IOException e) {
            if(dest != null) {
                dest.delete();
            }
            e.printStackTrace();
            return new Result<>(-1, "上传文件失败", false);
        } catch (InvalidAudioFrameException | CannotReadException | TagException e) {
            dest.delete();
            e.printStackTrace();
            return new Result<>(-1, "请上传音乐文件", false);
        }
    }
}

此时再通过 postman 测试,会返回错误信息:

上传 txt 文件(非MP3后缀文件也是):

那么 使用 AudioFileIO.read() 这个还需要抛出两个异常,在上面源码上也可以看到 ,一个是 ReadOnlyFileException,另一个是 TagException。第一个不难理解,看字面意思就知道是只读文件异常,但是具体什么情况会抛异常,我就不清楚了。那么第二个异常的话是 标签异常,我猜测应该 MP3文件中有某个标签,如果没有这个标签就会抛异常,这纯属个人猜测。

如果有大佬可以帮忙解读一下,那真的太感谢了!!!!!!

最后希望这篇博客可以带给大家帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值