首頁 > 科技

Win10竟會損壞使用者檔案?教你解決這個Bug

2021-06-06 03:00:33

  [PConline 資訊]如果你是一名音樂發燒友,那麼應該知道Flac這種常見的無損音樂格式。Flac音樂檔案支援metadata,使用者可以編輯metadata,讓音樂檔案帶有藝術家、所屬專輯、音軌等等資訊。通常來說,metadata和音訊資料並不相關,修改metadata並不會影響音訊本身。但是,近日微軟官方公佈了Win10中存在一個Bug,在Win10中用資源管理器修改Flac檔案的metadata,竟會導致音訊的損壞!

  根據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、複製以下字元,貼上到記事本中:

  # Copyright 2021 Microsoft

  # This script will repair a FLAC file that has been corrupted by Media Foundation in reference to KB5003430.

  # Refer to KB5003430 for further information

  param(

  [parameter(Mandatory=$true,

  HelpMessage="The path to the FLAC file that has been corrupted by Media Foundation",

  ValueFromRemainingArguments=$true)]

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

  [String]$File

  )

  # We need to back up the current file incase we have any errors

  $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 "Microsoft FLAC Repair Tool. This tool will repair a FLAC audio file that was corrupted when editing its details."

  Write-Output "Affected File: $FullPath"

  Write-Output "A backup of the file will be made: $BackupLocation"

  Write-Output "Do you wish to continue?"

  $choice=$host.ui.PromptForChoice("Fixing FLAC Script", "Do you wish to continue", ('&Yes', '&No'), 1)

  function ParseStreamInfoMetadataBlock([System.IO.FileStream]$stream)

  {

  $blockType = $stream.ReadByte()

  $lastBlock = ($blockType -shr 7) -ne 0

  $blockType = $blockType -band 0x7F

  if ($blockType -ne 0)

  {

  return $false

  }

  $blockSize = (($stream.ReadByte() -shl 16) -bor ($stream.ReadByte() -shl 8) -bor $stream.ReadByte())

  if ($blockSize -lt 34)

  {

  return $false

  }

  $minAudioBlockSize = ($stream.ReadByte() -shl 8) -bor $stream.ReadByte()

  $maxAudioBlockSize = ($stream.ReadByte() -shl 8) -bor $stream.ReadByte()

  if ($minAudioBlockSize -lt 16 -or $maxAudioBlockSize -lt 16)

  {

  return $false

  }

  $minFrameSize = (($stream.ReadByte() -shl 16) -bor ($stream.ReadByte() -shl 8) -bor $stream.ReadByte())

  $maxFrameSize = (($stream.ReadByte() -shl 16) -bor ($stream.ReadByte() -shl 8) -bor $stream.ReadByte())

  $sampleInfo = (($stream.ReadByte() -shl 24) -bor ($stream.ReadByte() -shl 16) -bor ($stream.ReadByte() -shl 8) -bor $stream.ReadByte())

  $sampleRate = $sampleInfo -shr 12

  $channelCount = (($sampleInfo -shr 9) -band 0x7) + 1

  $bitsPerSample = (($sampleInfo -shr 4) -band 0x1F) + 1

  [UInt64]$sampleCount = (($stream.ReadByte() -shl 24) -bor ($stream.ReadByte() -shl 16) -bor ($stream.ReadByte() -shl 8) -bor $stream.ReadByte())

  $sampleCount = (([UInt64]$sampleInfo -band 0xF) -shl 32) -bor $sampleCount

  $MD5HashBytes = New-Object byte[] 16

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

  $MD5Hash = [Guid]($MD5HashBytes)

  if ($sampleRate -eq 0)

  {

  return $false

  }

  # Passing these checks means that we likely have a stream info header and can rebuild the file

  Write-Output "File Stream Information"

  Write-Output "Sample Rate: $sampleRate"

  Write-Output "Audio Channels: $channelCount"

  Write-Output "Sample Depth: $bitsPerSample"

  Write-Output "MD5 Audio Sample Hash: $MD5Hash"

  return $true

  }

  if ($choice -eq 0)

  {

  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() -eq 0) {}

  # We now need to figure out where a valid FLAC metadata frame begins

  # We are likely pointing to the last byte of the size member so we'll seek back 4 bytes and retry

  $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)

  }

  # Insert the start code

  $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出現的問題。


IT145.com E-mail:sddin#qq.com