使用TagLib.Audio修改MP3标签时偶现Memory Stream Is Not Expandable错误求助
解决TagLib.Audio修改MP3标签时“memory stream is not expandable”错误
问题原因
你当前使用FileBytesAbstraction传入dto.MusicFile.File.GetBytes()返回的字节数组时,对应的内存流是固定长度、不可扩展的。当修改后的标签数据量超过原标签大小,TagLib需要扩展流空间以写入新数据,但固定长度流不支持此操作,因此抛出错误。
可行解决方案
方案1:自定义可扩展内存流的IFileAbstraction
实现基于MemoryStream的IFileAbstraction,MemoryStream默认支持动态扩展:
public class MemoryFileAbstraction : TagLib.IFileAbstraction { private readonly MemoryStream _stream; public string Name { get; } public MemoryFileAbstraction(string name, byte[] initialData) { Name = name; _stream = new MemoryStream(initialData); } public Stream ReadStream => _stream; public Stream WriteStream => _stream; public void CloseStream(Stream stream) { // 无需额外处理,using语句会自动管理流生命周期 } }
替换原创建TagLib.File的代码:
using var music = TagLib.File.Create(new MemoryFileAbstraction(dto.MusicFile.Name, dto.MusicFile.File.GetBytes()));
保存完成后读取修改后的字节:
music.Save(); // 重置流位置到起始处 ((MemoryStream)music.FileAbstraction.ReadStream).Position = 0; // 读取所有字节 var modifiedBytes = ((MemoryStream)music.FileAbstraction.ReadStream).ToArray();
方案2:使用本地临时文件(修正版)
如果之前临时文件方案失败,可能是路径或读写逻辑问题,按以下步骤操作:
// 生成唯一临时文件路径 var tempPath = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.mp3"); // 将原文件字节写入临时文件 File.WriteAllBytes(tempPath, dto.MusicFile.File.GetBytes()); // 打开临时文件修改标签 using var music = TagLib.File.Create(tempPath); // 执行标签修改操作(你的原有代码) music.Tag.Performers = await db.Artists.Where(a => dto.Artists.Contains(a.Id)) .Select(a => a.ArtisticName) .ToArrayAsync(); // ...其他标签修改代码... music.Save(); // 读取修改后的文件字节 var modifiedBytes = File.ReadAllBytes(tempPath); // 删除临时文件 File.Delete(tempPath);
方案3:强制使用可扩展的标签格式
部分老MP3使用固定大小的ID3v1标签,修改时容易触发空间不足问题,强制TagLib使用ID3v2标签:
// 在Save前设置标签类型为ID3v2 music.TagTypes = TagTypes.Id3v2; music.Save();
额外注意点
原代码中music.RFind(byteMusic)是无效操作,RFind需要传入非空的ByteVector进行查找,若要获取修改后的文件字节,参考方案1或方案2的读取逻辑。
内容的提问来源于stack exchange,提问作者NoobPogrammer
相关产品推荐
相关产品推荐

