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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 11:55:30