使用PowerShell更新Jar文件致损坏,Java无法加载Class求助
PowerShell更新Jar包后Class无法加载的问题解决
问题描述
用PowerShell调用[System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile替换Jar包内的class文件后,Java无法加载该class;但用7Zip执行相同替换操作则完全正常。经排查,问题出在PowerShell修改了Zip条目的Characteristic标签,导致该class不再被标记为描述符,进而被Java忽略。
原执行代码
Add-Type -Assembly System.IO.Compression.FileSystem $enc = [System.Text.Encoding]::UTF8 $zipFile = [IO.Compression.ZipFile]::Open('.\destjar.jar',([System.IO.Compression.ZipArchiveMode]::Update),$enc) $foundFile=$zipFile.Entries.Where({ $_.FullName -like '*dest.class' }, 'First') [System.IO.Compression.ZipFileExtensions]::ExtractToFile($foundFile[0], "temp.class",$true) # some class modification here... $foundFile.Delete() [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zipFile,'temp.class','com\xxx\yyy\zzz\dest.class') $zipFile.Dispose()
问题根源
Jar是遵循特定规范的Zip文件,其中class文件对应的Zip条目必须设置Characteristic值为0x800(描述符标志),Java才会将其识别为有效class文件。但.NET的CreateEntryFromFile方法默认不会设置这个标志,导致生成的条目不符合Jar规范,最终无法被加载。
修复方案
通过反射修改新创建条目的Characteristic属性,将其设置为0x800,确保符合Jar规范。修改后的代码如下:
Add-Type -Assembly System.IO.Compression.FileSystem $enc = [System.Text.Encoding]::UTF8 $zipFile = [IO.Compression.ZipFile]::Open('.\destjar.jar',([System.IO.Compression.ZipArchiveMode]::Update),$enc) $foundFile=$zipFile.Entries.Where({ $_.FullName -like '*dest.class' }, 'First') [System.IO.Compression.ZipFileExtensions]::ExtractToFile($foundFile[0], "temp.class",$true) # 此处执行class文件修改操作... $foundFile.Delete() # 创建新条目 $newEntry = [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zipFile,'temp.class','com\xxx\yyy\zzz\dest.class') # 通过反射修改Characteristic为0x800(描述符标志) $entryField = $newEntry.GetType().GetField('_zipArchiveEntry', [System.Reflection.BindingFlags]'NonPublic, Instance') $zipArchiveEntry = $entryField.GetValue($newEntry) $characteristicField = $zipArchiveEntry.GetType().GetField('_characteristics', [System.Reflection.BindingFlags]'NonPublic, Instance') $characteristicField.SetValue($zipArchiveEntry, 0x800) $zipFile.Dispose()
替代方案
若不想使用反射,也可以手动创建条目并写入文件,同时设置正确属性:
Add-Type -Assembly System.IO.Compression.FileSystem $enc = [System.Text.Encoding]::UTF8 $zipFile = [IO.Compression.ZipFile]::Open('.\destjar.jar',([System.IO.Compression.ZipArchiveMode]::Update),$enc) $foundFile=$zipFile.Entries.Where({ $_.FullName -like '*dest.class' }, 'First') [System.IO.Compression.ZipFileExtensions]::ExtractToFile($foundFile[0], "temp.class",$true) # 此处执行class文件修改操作... $foundFile.Delete() $entryName = 'com\xxx\yyy\zzz\dest.class' # 创建条目并设置最优压缩级别 $newEntry = $zipFile.CreateEntry($entryName, [System.IO.Compression.CompressionLevel]::Optimal) # 修改Characteristic属性 $entryField = $newEntry.GetType().GetField('_zipArchiveEntry', [System.Reflection.BindingFlags]'NonPublic, Instance') $zipArchiveEntry = $entryField.GetValue($newEntry) $characteristicField = $zipArchiveEntry.GetType().GetField('_characteristics', [System.Reflection.BindingFlags]'NonPublic, Instance') $characteristicField.SetValue($zipArchiveEntry, 0x800) # 将修改后的class写入条目 $stream = $newEntry.Open() $fileStream = [System.IO.File]::OpenRead('temp.class') $fileStream.CopyTo($stream) $fileStream.Close() $stream.Close() $zipFile.Dispose()
内容的提问来源于stack exchange,提问作者aeon
相关产品推荐
相关产品推荐

