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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 21:08:33