Molet

Windows 10竟会损坏用户文件?教你解决这个Bug

Molet 运维技术 2022-11-13 368浏览 0

如果你是一名音乐发烧友,那么应该知道Flac这种常见的无损音乐格式。Flac音乐文件支持metadata,用户可以编辑metadata,让音乐文件带有艺术家、所属专辑、音轨等等信息。通常来说,metadata和音频数据并不相关,修改metadata并不会影响音频本身。但是,近日微软官方公布了Win10中存在一个Bug,在Win10中用资源管理器修改Flac文件的metadata,竟会导致音频的损坏!

Windows 10竟会损坏用户文件?教你解决这个Bug

根据Windows Latest的报道,微软最新发布的一份支持文件披露,如果在Win10的2004或者更高版本中,使用文件资源管理器修改Flac音乐文件的metadata,就会损耗Flac音频文件。这个Bug在Win10专业版、家庭版、企业版、工作站版乃至其他版本的Win10中均有出现。

根据微软本月早些时候发布的支持文件,Win10的文件资源管理器导致了这个错误,它破坏了Flac文件头包含的ID3框架也就是metadata,而这个ID3框架负责存储音频的注释,例如音乐标题、艺术家、专辑、曲目编号等。在Win10上,Flac的处理程序忽视了ID3框架,该程序认为Flac文件在使用4字节的文件头,当Flac文件被Win10编辑的时候,ID3框架被覆盖了,导致没有了开始代码,导致了音乐播放器无法识别被修改后的文件。

因此,在Win10中,如果你直接用文件资源管理器修改Flac音乐文件的标题、艺术家等metadata,会导致该文件无法播放。

幸运的是,微软已经确定了Bug的根本原因,用户可以通过Windows Update升级KB5003214补丁进行修复。

在KB5003214补丁中,微软确认了上文提到的错误已经被修复,修改了Flac的标题、艺术家等metadata后,Flac不会再变得无法播放。而对于已经损坏了的Flac文件,微软则发布了一个PowerShell脚本来进行修复,运行该脚本后Flac文件即可重新播放,不过已经从ID3框架中丢失了的metadata信息并不能恢复。

下面是利用PowerShell脚本修复Flac文件的具体方法。

1、开启记事本;

2、复制以下字符,粘贴到记事本中:

#Copyright2021Microsoft

 #ThisscriptwillrepairaFLACfilethathasbeencorruptedbyMediaFoundationinreferencetoKB5003430.

 #RefertoKB5003430forfurtherinformation

 param(

 [parameter(Mandatory=$true,

 HelpMessage="ThepathtotheFLACfilethathasbeencorruptedbyMediaFoundation",

 ValueFromRemainingArguments=$true)]

 [ValidateScript({-not[String]::IsNullOrEmpty($_)-and(Test-Path$_)})]

 [String]$File

 )

 #Weneedtobackupthecurrentfileincasewehaveanyerrors

 $FileDirectory=Split-Path-Resolve$File

 $Filename=Split-Path-Leaf-Resolve$File

 $FullPath=Join-Path-Resolve$FileDirectory$Filename

 $Filename=[String]::Format("Backup_{0:yyyyMMdd_hhmmss}_{1}",[DateTime]::Now,$Filename)

 $BackupLocation=Join-Path$FileDirectory$Filename

 Write-Output"MicrosoftFLACRepairTool.ThistoolwillrepairaFLACaudiofilethatwascorruptedwheneditingitsdetails."

 Write-Output"AffectedFile:$FullPath"

 Write-Output"Abackupofthefilewillbemade:$BackupLocation"

 Write-Output"Doyouwishtocontinue?"

 $choice=$host.ui.PromptForChoice("FixingFLACScript","Doyouwishtocontinue",('&Yes','&No'),1)

 functionParseStreamInfoMetadataBlock([System.IO.FileStream]$stream)

 {

 $blockType=$stream.ReadByte()

 $lastBlock=($blockType-shr7)-ne0

 $blockType=$blockType-band0x7F

 if($blockType-ne0)

 {

 return$false

 }

 $blockSize=(($stream.ReadByte()-shl16)-bor($stream.ReadByte()-shl8)-bor$stream.ReadByte())

 if($blockSize-lt34)

 {

 return$false

 }

 $minAudioBlockSize=($stream.ReadByte()-shl8)-bor$stream.ReadByte()

 $maxAudioBlockSize=($stream.ReadByte()-shl8)-bor$stream.ReadByte()

 if($minAudioBlockSize-lt16-or$maxAudioBlockSize-lt16)

 {

 return$false

 }

 $minFrameSize=(($stream.ReadByte()-shl16)-bor($stream.ReadByte()-shl8)-bor$stream.ReadByte())

 $maxFrameSize=(($stream.ReadByte()-shl16)-bor($stream.ReadByte()-shl8)-bor$stream.ReadByte())

 $sampleInfo=(($stream.ReadByte()-shl24)-bor($stream.ReadByte()-shl16)-bor($stream.ReadByte()-shl8)-bor$stream.ReadByte())

 $sampleRate=$sampleInfo-shr12

 $channelCount=(($sampleInfo-shr9)-band0x7)+1

 $bitsPerSample=(($sampleInfo-shr4)-band0x1F)+1

 [UInt64]$sampleCount=(($stream.ReadByte()-shl24)-bor($stream.ReadByte()-shl16)-bor($stream.ReadByte()-shl8)-bor$stream.ReadByte())

 $sampleCount=(([UInt64]$sampleInfo-band0xF)-shl32)-bor$sampleCount

 $MD5HashBytes=New-Objectbyte[]16

 $stream.Read($MD5HashBytes,0,$MD5HashBytes.Length)

 $MD5Hash=[Guid]($MD5HashBytes)

 if($sampleRate-eq0)

 {

 return$false

 }

 #Passingthesechecksmeansthatwelikelyhaveastreaminfoheaderandcanrebuildthefile

 Write-Output"FileStreamInformation"

 Write-Output"SampleRate:$sampleRate"

 Write-Output"AudioChannels:$channelCount"

 Write-Output"SampleDepth:$bitsPerSample"

 Write-Output"MD5AudioSampleHash:$MD5Hash"

 return$true

 }

 if($choice-eq0)

 {

 Copy-Item$FullPath-Destination$BackupLocation-Force

 $stream=[System.IO.File]::Open($FullPath,[System.IO.FileMode]::Open)

 $stream.Seek(4,[System.IO.SeekOrigin]::Begin)

 while($stream.ReadByte()-eq0){}

 #WenowneedtofigureoutwhereavalidFLACmetadataframebegins

 #Wearelikelypointingtothelastbyteofthesizemembersowe'llseekback4bytesandretry

 $flacDataStartPosition=$stream.Position-4

 $stream.Seek($flacDataStartPosition,[System.IO.SeekOrigin]::Begin)

 while(-not(ParseStreamInfoMetadataBlock($stream)))

 {

 $flacDataStartPosition=$flacDataStartPosition+1

 $stream.Seek($flacDataStartPosition,[System.IO.SeekOrigin]::Begin)

 }

 #Insertthestartcode

 $stream.Seek($flacDataStartPosition,[System.IO.SeekOrigin]::Begin)

 if(Test-Path"$FullPath.tmp")

 {

 Remove-Item"$FullPath.tmp"

 }

 $fixedStream=[System.IO.File]::Open("$FullPath.tmp",[System.IO.FileMode]::CreateNew)

 [byte[]]$startCode=[char[]]('f','L','a','C');

 $fixedStream.Write($startCode,0,$startCode.Length)

 $stream.CopyTo($fixedStream)

 $stream.Close()

 $fixedStream.Close()

 Move-Item-Force"$FullPath.tmp"$FullPath

 }

3、保存文件,在“另存为”对话框中,将目录定位到你想要保存PowerShell脚本的位置;

4、在文件名输入框中,输入“FixFlacFiles.ps1”,将另存为文件的类型更改为Text Documents (*.txt);

5、进入到你保存该PowerShell脚本的目录;

6、右键点击刚刚保存的脚本,然后选择“使用PowerShell运行”;

7、出现提示时,输入无法播放的Flac文件的文件名,然后按下回车键。

微软建议大家安装本月推送的可选累积更新,以避免修改Flac文件metadata出现的问题。

继续浏览有关 系统运维 的文章
发表评论