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

Jenkins Pipeline中Groovy字符串比较异常,无法读取Properties值

问题:Jenkins Pipeline读取UTF16LE编码文件时Properties键匹配失败

在Jenkins Pipeline中执行Groovy代码读取UTF16LE编码的version.txt文件,尝试获取FullVersionStr属性时出现异常:

  • 无论使用props["FullVersionStr"]、props.FullVersionStr,还是遍历Properties进行字符串比较(==、equalsIgnoreCase()),均无法匹配到该属性
  • 输出显示Properties中存在FullVersionStr键,但取值始终为null

相关代码与执行输出

Jenkins Pipeline代码

pipeline {
  agent any
  parameters { [...skip...] } 
  stages {
    stage('Build') {
      steps { [...skip...] }
      post {
        always {
          script{
            try {
              echo "* loading ini: ${env.buildVerInfoFile} ..."
              def content = readFile "${env.buildVerInfoFile}"
              Properties props = new Properties()
              InputStream is = new ByteArrayInputStream(content.getBytes());
              props.load(is)
              env.VN = props["FullVersionStr"]
              echo " = ver: ${env.VN}; props:${props.toString()}"
              env.VN = props.FullVersionStr
              echo " = ver.a: ${env.VN}; "
              
              def toFind = "FullVersionStr"
              props.each { prop, val ->
                if(prop in ["metaClass","class"]) return
                def pn = prop.toString()
                def q = (pn == toFind)
                if(q) {
                    env.VN = val
                    echo " = set vn: ${env.VN}/${val}; "
                }
                echo " == (${q}) [${pn}]: ${val}"
              }
              echo " = ver.b: ${env.VN}; "

            } catch (Exception exc) {
              echo 'ERR: exception occurred: ' + exc.toString()
            }
          }
          [...skip...]  
        }
        success { [...skip...] }
      }
    }
  }
}

执行输出

loading ini: C:\XBuild.main\build\log\ARC\version.txt ... 
[Pipeline] readFile 
[Pipeline] echo = ver: null; props:{=, FullVersionStr=3.3.0.152, ReleaseVersionStr=2020.1.1.1, BuildStarted=2025-04-06,14:53:27.193, i??i??dummy=123} 
[Pipeline] echo = ver.a: null; 
[Pipeline] echo == (false) : 
[Pipeline] echo == (false) FullVersionStr: 3.3.0.152 
[Pipeline] echo == (false) ReleaseVersionStr: 2020.1.1.1 
[Pipeline] echo == (false) BuildStarted: 2025-04-06,14:53:27.193 
[Pipeline] echo == (false) i??i??dummy: 123 
[Pipeline] echo = ver.b: null; 
[Pipeline] } 
[Pipeline] // script   

环境信息:Jenkins 2.492.3、JDK 21、Groovy 2.4.21、Windows Server 2022 Std,version.txt由PowerShell生成,编码为UTF16LE。

原因分析

核心问题是编码解码不匹配:

  1. readFile默认使用系统编码(Windows下通常为GBK/UTF-8)读取UTF16LE编码的文件,导致内容被错误解码,字符串中混入不可见的乱码字符或字节序标记(BOM)
  2. 错误解码后的内容转成字节流加载到Properties时,键名的实际值并非表面显示的FullVersionStr,而是包含隐藏字符的字符串,因此直接用字面量匹配失败
  3. 输出中的空键{=,...}和乱码键i??i??dummy,都是UTF16LE编码被错误解码的典型表现

解决方案

方案1:指定编码读取文件

使用readFile的encoding参数,直接以UTF-16LE编码读取文件,避免转码错误:

def content = readFile file: "${env.buildVerInfoFile}", encoding: "UTF-16LE"
Properties props = new Properties()
// 将正确解码的字符串转成UTF16LE字节流加载
props.load(new ByteArrayInputStream(content.getBytes("UTF-16LE")))

方案2:直接读取文件字节流(更可靠)

跳过readFile的中间转码,直接读取文件字节流并指定UTF16LE编码加载,同时手动处理UTF16LE的BOM(0xFFFE):

File verFile = new File("${env.buildVerInfoFile}")
Properties props = new Properties()
verFile.withInputStream { is ->
    // 跳过UTF16LE的BOM标记
    int b1 = is.read()
    int b2 = is.read()
    if (!(b1 == 0xFF && b2 == 0xFE)) {
        is.reset() // 不是BOM则重置流指针
    }
    // 用UTF16LE编码读取流内容
    props.load(new InputStreamReader(is, "UTF-16LE"))
}

调试排查技巧

如果仍有问题,可以输出键名的字节码,确认是否存在隐藏字符:

props.each { prop, val ->
    def pn = prop.toString()
    echo "键名: ${pn}, 十六进制字节: ${pn.getBytes('UTF-8').encodeHex()}"
}

对比正常FullVersionStr的字节码,即可定位是否存在乱码或隐藏字符。

修改后的完整Script示例

script{
  try {
    echo "* loading ini: ${env.buildVerInfoFile} ..."
    // 采用方案2:直接读取文件字节流
    File verFile = new File("${env.buildVerInfoFile}")
    Properties props = new Properties()
    verFile.withInputStream { is ->
        int b1 = is.read()
        int b2 = is.read()
        if (!(b1 == 0xFF && b2 == 0xFE)) {
            is.reset()
        }
        props.load(new InputStreamReader(is, "UTF-16LE"))
    }

    env.VN = props["FullVersionStr"]
    echo " = ver: ${env.VN}; props:${props.toString()}"
    env.VN = props.FullVersionStr
    echo " = ver.a: ${env.VN}; "
    
    def toFind = "FullVersionStr"
    props.each { prop, val ->
      if(prop in ["metaClass","class"]) return
      def pn = prop.toString()
      def q = (pn == toFind)
      if(q) {
          env.VN = val
          echo " = set vn: ${env.VN}/${val}; "
      }
      echo " == (${q}) [${pn}]: ${val}"
    }
    echo " = ver.b: ${env.VN}; "

  } catch (Exception exc) {
    echo 'ERR: exception occurred: ' + exc.toString()
  }
}

内容的提问来源于stack exchange,提问作者dmitry_bond

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 13:55:58