首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

MP3 ID3v1 TAG 解析全解析:C# 讀取標題、歌手、專輯、年份、流派完整實作

     編輯:關於C語言

ID3v1 TAG 結構規格

位於 MP3 檔案**最後 128 位元組**,固定長度,結構如下:

欄位長度位移說明
Tag 標識30-2必為 "TAG"
Title303-32曲目標題
Artist3033-62歌手名稱
Album3063-92專輯名稱
Year493-96發行年份
Comment3097-126備註(v1.1 最後 1 位元組為 Track Number)
Genre1127流派代碼 (0-79, 255=Unknown)

欄位不足以空白 (0x20) 或 null (0x00) 填充。WinAmp 習慣用空白填充。

流派代碼對照表(節錄)


0: Blues      1: Classic Rock   2: Country     3: Dance      4: Disco
5: Funk       6: Grunge         7: Hip-Hop     8: Jazz       9: Metal
10: New Age   11: Oldies        12: Other      13: Pop       14: R&B
15: Rap       16: Reggae        17: Rock       18: Techno    19: Industrial
20: Alternative  21: Ska        22: Death Metal 23: Pranks    24: Soundtrack
... 79: Hard Rock, 255: Unknown

C# 解析類別完整實作


using System;
using System.IO;
using System.Text;

public class Mp3TagReader {
    public string Title { get; private set; }
    public string Artist { get; private set; }
    public string Album { get; private set; }
    public string Year { get; private set; }
    public string Comment { get; private set; }
    public string Genre { get; private set; }
    public byte TrackNumber { get; private set; } // ID3v1.1
    public bool HasTag { get; private set; }

    private static readonly string[] Genres = new[] {
        "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge",
        "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B",
        "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska",
        "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop",
        "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental",
        "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "Alt. Rock",
        "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
        "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial",
        "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy",
        "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle",
        "Native American", "Cabaret", "New Wave", "Psychedelic", "Rave",
        "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz",
        "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock"
    };

    public Mp3TagReader(string filePath) {
        Parse(filePath);
    }

    public void Parse(string filePath) {
        using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) {
            if (fs.Length < 128) { HasTag = false; return; }

            fs.Seek(-128, SeekOrigin.End);
            byte[] tag = new byte[128];
            fs.Read(tag, 0, 128);

            // 驗證 TAG 標識
            string tagId = Encoding.Default.GetString(tag, 0, 3);
            if (tagId != "TAG") { HasTag = false; return; }

            HasTag = true;
            Title = Clean(Encoding.Default.GetString(tag, 3, 30));
            Artist = Clean(Encoding.Default.GetString(tag, 33, 30));
            Album = Clean(Encoding.Default.GetString(tag, 63, 30));
            Year = Clean(Encoding.Default.GetString(tag, 93, 4));
            Comment = Clean(Encoding.Default.GetString(tag, 97, 30));
            Genre = Genres.Length > tag[127] ? Genres[tag[127]] : "Unknown";

            // ID3v1.1: Comment 最後一位若為 0,倒數第二位為 Track Number
            if (tag[125] == 0 && tag[126] != 0) {
                TrackNumber = tag[126];
                Comment = Clean(Encoding.Default.GetString(tag, 97, 28)); // 前 28 位
            }
        }
    }

    private string Clean(string s) {
        return s.Trim('\0', ' '); // 移除前後空白與 null
    }
}

使用範例


var tag = new Mp3TagReader(@"C:\Music\song.mp3");
if (tag.HasTag) {
    Console.WriteLine($"標題: {tag.Title}");
    Console.WriteLine($"歌手: {tag.Artist}");
    Console.WriteLine($"專輯: {tag.Album}");
    Console.WriteLine($"年份: {tag.Year}");
    Console.WriteLine($"流派: {tag.Genre}");
    Console.WriteLine($"軌道: {tag.TrackNumber}");
    Console.WriteLine($"備註: {tag.Comment}");
} else {
    Console.WriteLine("無 ID3v1 TAG");
}

進階:ID3v2 / 圖片封面 / 多語言支援

ID3v1 侷限極大(長度固定、無 Unicode、無封面)。實務建議直接使用成熟庫:

  • TagLib Sharp (taglib-sharp):跨平台、支援 ID3v1/v2.3/v2.4、APE、Vorbis Comments、MP4、FLAC 等,可讀寫封面圖片。
  • NAudio:含 `Id3v2Tag` 類別,輕量級。
  • MusicBrainz / AcoustID:線上指紋辨識補全元資料。

TagLib Sharp 讀寫範例


using TagLib;

var f = TagLib.File.Create("song.mp3");
Console.WriteLine(f.Tag.Title);
Console.WriteLine(f.Tag.FirstAlbumArtist);
Console.WriteLine(f.Tag.Year);
Console.WriteLine(f.Tag.Genres.FirstOrDefault());

// 寫入標籤
f.Tag.Title = "新標題";
f.Tag.Artists = new[] { "新歌手" };
f.Tag.Pictures = new[] { new TagLib.Picture(new TagLib.ByteVector(File.ReadAllBytes("cover.jpg"))) };
f.Save();

總結

ID3v1 解析邏輯簡單,適合教學或極簡場景。實際專案**強烈建議使用 TagLib Sharp**,一次搞定所有格式、編碼、封面、版本相容問題,避免重複造輪子。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved