国密算法 SM2 SM3 SM4

//SM2
package com.lzy.gm;

import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.util.encoders.Hex;

import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.ECGenParameterSpec;

/**
 * 国密sm2算法
 * 参考链接:https://blog.csdn.net/qq_39120741/article/details/130937860
 */
public class SM2 {
    private final KeyPair mKeyPair;
    public SM2() throws Exception {
        mKeyPair = initKey();
    }

    /**
     * sm2加密算法
     * @param pubkey:公钥
     * @param plainData:要加密的字符串
     * @return:加密结果
     */
    public static String encrypt(PublicKey pubkey,String plainData) {
        try {
            SM2Engine sm2Engine = MySm2Engine.createMySm2Engine(pubkey,null,MySm2Engine.Type_Encode);
            //encrypt data
            byte[] bytes = null;
            try {
                byte[] in = plainData.getBytes(StandardCharsets.UTF_8);
                bytes = sm2Engine.processBlock(in,0, in.length);
            }
            catch (Exception e) {
                System.out.println("SM2加密失败:");
            }
            return Hex.toHexString(bytes);
        }catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * sm2解密算法
     * @param priKey:私钥
     * @param cipherData:要解密的字符串
     * @return
     */
    public static String decrypt(PrivateKey priKey,String cipherData) {
        try {
            //init engine
            SM2Engine sm2Engine = MySm2Engine.createMySm2Engine(null,priKey,MySm2Engine.Type_Decode);

            //decrypt data
            byte[] cipherDataByte = Hex.decode(cipherData);
            byte[] bytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
            return new String(bytes, StandardCharsets.UTF_8);
        }catch (Exception e) {
            System.out.println("SM2解密失败:");
        }
        return null;
    }

    /**
     * 创建密钥对
     * 原文链接:https://blog.csdn.net/liranke/article/details/128814638
     * @return 密钥对KeyPair
     * @throws Exception
     */
    public static KeyPair initKey()  throws Exception{
        try {
            ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
            // 获取一个椭圆曲线类型的密钥对生成器
            final KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
            // 使用SM2参数初始化生成器
            kpg.initialize(sm2Spec);
            // 获取密钥对
            KeyPair keyPair = kpg.generateKeyPair();
            return keyPair;
        }catch (Exception e) {
            throw new Exception(e);
        }
    }

    /**
     * 签名
     *
     * @param data
     * @param privateKey
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws SignatureException
     */
    public static String sign(String data, PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
        // 生成SM2sign with sm3 签名验签算法实例
        Signature signature = Signature.getInstance(
                GMObjectIdentifiers.sm2sign_with_sm3.toString(), new BouncyCastleProvider());
         // 签名
         // 签名需要使用私钥,使用私钥 初始化签名实例
        signature.initSign(privateKey);
        // 写入签名原文到算法中
        signature.update(data.getBytes(StandardCharsets.UTF_8));
        // 计算签名值
        byte[] signatureValue = signature.sign();
        return Hex.toHexString(signatureValue);
    }

    /**
     * 验签
     *
     * @param publicKey
     * @param plainText
     * @param signatureValue
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws SignatureException
     */
    public static boolean verify(PublicKey publicKey, String plainText, String signatureValue) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
        // 生成SM2sign with sm3 签名验签算法实例
        Signature signature = Signature.getInstance(
                GMObjectIdentifiers.sm2sign_with_sm3.toString(), new BouncyCastleProvider());
        /*
         * 验签
         * 签名需要使用公钥,使用公钥 初始化签名实例
         */
        signature.initVerify(publicKey);
        // 写入待验签的签名原文到算法中
        signature.update(plainText.getBytes(StandardCharsets.UTF_8));
        // 验签
        return signature.verify(Hex.decode(signatureValue));
    }

    public static void main(String[] args) throws Exception {
        String dataStr = "hello ,2023!";
        SM2 sm2CryptTools= new SM2();
        KeyPair keyPair = sm2CryptTools.mKeyPair;

        System.out.println("原始明文:" + dataStr);
        String resData = sm2CryptTools.encrypt(keyPair.getPublic(),dataStr);
        System.out.println("SM2加密后密文:" + resData);

        String resData2 = sm2CryptTools.decrypt(keyPair.getPrivate(),resData);
        System.out.println("SM2解密后明文:" + resData2);

        String sign = sign(dataStr, keyPair.getPrivate());
        System.out.println("签名值:" + sign);
        System.out.println("dataStr:" + dataStr);

        boolean verify = verify(keyPair.getPublic(), dataStr, sign);
        System.out.println("验签结果:" + verify);
    }
}

/**
 * SM2引擎类
 */
class MySm2Engine {
    public static final int Type_Encode = 0;
    public static final int Type_Decode = 1;

    /**
     * 创建一个SM2引擎
     * @param pubKey
     * @param priKey
     * @param enOrde
     * @return
     * @throws Exception
     */
    public static SM2Engine createMySm2Engine(PublicKey pubKey,PrivateKey priKey,int enOrde) throws Exception {
        if (enOrde == Type_Encode) {
            ECPublicKeyParameters ecPublicKeyParameters = null;
            if (pubKey instanceof BCECPublicKey) {
                BCECPublicKey bcPubKey = (BCECPublicKey) pubKey;
                ECParameterSpec ecParameterSpec = bcPubKey.getParameters();
                ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(),
                        ecParameterSpec.getG(), ecParameterSpec.getN());
                ecPublicKeyParameters = new ECPublicKeyParameters(bcPubKey.getQ(),ecDomainParameters);
            }
            SM2Engine sm2Engine = new SM2Engine();
            sm2Engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom()));
            return sm2Engine;
        }else {

            BCECPrivateKey bcecPrivateKey = (BCECPrivateKey) priKey;
            ECParameterSpec ecParameterSpec = bcecPrivateKey.getParameters();
            ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(),
                    ecParameterSpec.getG(), ecParameterSpec.getN());
            ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(bcecPrivateKey.getD(),
                    ecDomainParameters);
            SM2Engine sm2Engine = new SM2Engine();
            sm2Engine.init(false, ecPrivateKeyParameters);
            return sm2Engine;
        }
    }
}

// SM3

package com.lzy.util;

import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;

import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;

/**
 * 国密SM3算法
 */
public class SM3 {
    private static final String ENCODING = "UTF-8";
    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 计算数据摘要,
     * 源数据发生变化时,计算得到的摘要值不同,一般用于数据完整性校验;
     *
     * @param srcData
     * @return
     */
    public static byte[] hash(byte[] srcData) {
        SM3Digest digest = new SM3Digest();
        //update the message digest with a single byte.
        digest.update(srcData, 0, srcData.length);
        byte[] hash = new byte[digest.getDigestSize()];
        //close the digest, producing the final digest value.
        digest.doFinal(hash, 0);
        return hash;
    }

    /**
     * 通过密钥进行加密
     * @explain 指定密钥进行加密
     * @param key 密钥
     * @param srcData 被加密的byte数组
     * @return
     */
    public static byte[] hmac(byte[] key, byte[] srcData) {
        KeyParameter keyParameter = new KeyParameter(key);
        SM3Digest digest = new SM3Digest();
        HMac mac = new HMac(digest);
        mac.init(keyParameter);
        mac.update(srcData, 0, srcData.length);
        byte[] result = new byte[mac.getMacSize()];
        mac.doFinal(result, 0);
        return result;
    }

    public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchProviderException {
        String data = "测试国密算法。。。";
        // 计算数据摘要
        byte[] hash = hash(data.getBytes(StandardCharsets.UTF_8));
        String s = ByteUtils.toHexString(hash);
        System.out.println(s);

        byte[] key = SM4.generateKey();
        byte[] hmac = hmac(key, data.getBytes(StandardCharsets.UTF_8));
        System.out.println(ByteUtils.toHexString(hmac));
    }
}

// Sm4
package com.lzy.cipher;

import com.lzy.util.ByteUtils;
import com.lzy.util.FileUtils;
import com.lzy.util.Sm3Utils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.*;

/**
 * @Description SM2实现工具类
 * @date 2021/11/24 17:10
 */
public class Sm4Util {
    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public static final String ALGORITHM_NAME = "SM4";
    public static final String DEFAULT_KEY = "random_seed";

    // 128-32位16进制;256-64位16进制
    public static final int DEFAULT_KEY_SIZE = 128;

    public static byte[] generateKey() throws NoSuchAlgorithmException, NoSuchProviderException {
        return generateKey(DEFAULT_KEY, DEFAULT_KEY_SIZE);
    }

    public static byte[] generateKey(String seed) throws NoSuchAlgorithmException, NoSuchProviderException {
        return generateKey(seed, DEFAULT_KEY_SIZE);
    }

    public static byte[] generateKey(String seed, int keySize) throws NoSuchAlgorithmException, NoSuchProviderException {
        KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
        if (null != seed && !"".equals(seed)) {
            random.setSeed(seed.getBytes());
        }
        kg.init(keySize, random);
        return kg.generateKey().getEncoded();
    }

    /**
     * @description 加密
     */
    public static byte[] encrypt(String algorithmName, byte[] key, byte[] iv, byte[] data) throws Exception {
        return sm4core(algorithmName, Cipher.ENCRYPT_MODE, key, iv, data);
    }

    /**
     * @description 解密
     */
    public static byte[] decrypt(String algorithmName, byte[] key, byte[] iv, byte[] data) throws Exception {
        return sm4core(algorithmName, Cipher.DECRYPT_MODE, key, iv, data);
    }

    private static byte[] sm4core(String algorithmName, int type, byte[] key, byte[] iv, byte[] data) throws Exception {
        Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
        Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);
        if (algorithmName.contains("/ECB/")) {
            cipher.init(type, sm4Key);
        } else {
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
            cipher.init(type, sm4Key, ivParameterSpec);
        }

        return cipher.doFinal(data);
    }

    public static void main(String[] args) throws Exception {
//        byte[] key = generateKey();
//        System.out.println("key:" + new String(key));
//        String iv = "1234567890aabcba";
//        String plain = "testabc";
//
//        byte[] encrypt = encrypt("SM4/CBC/PKCS7PADDING", key, iv.getBytes(StandardCharsets.UTF_8), plain.getBytes());
//        byte[] decrypt = decrypt("SM4/CBC/PKCS7PADDING", key, iv.getBytes(StandardCharsets.UTF_8), encrypt);
//        System.out.println(new String(decrypt).equals(plain));

//        byte[] key = sm4ByFileEn();
//        System.out.println(ByteUtils.byteArrToHexStr(key));

        String key = ByteUtils.byteArrToHexStr(generateKey());
        String iv = "1234567890aabcba";

        String sourceFilePath = "D:\\workspace\\cipherTest\\plain.txt";
        String enFilePath = "D:\\workspace\\cipherTest\\cipher.txt";
        String deFilePath = "D:\\workspace\\cipherTest\\decrypt.txt";

//        sm4ByFile(Cipher.ENCRYPT_MODE, sourceFilePath, enFilePath, key, iv);
        sm4ByFile(Cipher.DECRYPT_MODE, enFilePath, deFilePath, key, iv);
//        byte[] en = FileUtils.toByteArrayMapped(enFilePath);
//        byte[] decrypt = decrypt("SM4/CBC/PKCS7PADDING", ByteUtils.hexStrToByteArr(key),
//                iv.getBytes(StandardCharsets.UTF_8), en);
//
//        byte[] pBytes = FileUtils.toByteArrayMapped(sourceFilePath);
//        byte[] pHash = Sm3Utils.hash(pBytes);
//
        byte[] deBytes = FileUtils.toByteArrayMapped(deFilePath);
//        byte[] deHash = Sm3Utils.hash(decrypt);
//
//        System.out.println(new String(pHash).equals(new String(deHash)));

        byte[] plain = FileUtils.toByteArrayMapped(sourceFilePath);
        byte[] encrypt = encrypt("SM4/CBC/PKCS7PADDING", ByteUtils.hexStrToByteArr(key),
                iv.getBytes(StandardCharsets.UTF_8), plain);
        FileUtils.byteToFile(enFilePath,encrypt);
        sm4ByFile(Cipher.DECRYPT_MODE, enFilePath, deFilePath, key, iv);
        byte[] de = FileUtils.toByteArrayMapped(deFilePath);

        byte[] hash = Sm3Utils.hash(plain);
        byte[] dec = Sm3Utils.hash(de);
        System.out.println(new String(hash).equals(new String(dec)));

    }

    private static void sm4ByFile(int type, String sourceFilePath, String destFilePath, String key, String iv)
            throws Exception {
        final String algorithmName = "SM4/CBC/PKCS7PADDING";
        final String ALGORITHM_NAME = "SM4";
        // 加密
        File sourceFile = new File(sourceFilePath);
        File destFile = new File(destFilePath);
        if (!sourceFile.exists() && !sourceFile.isFile()) {
            throw new IllegalArgumentException("加密源文件不存在");
        }
        if (!destFile.getParentFile().exists()) {
            destFile.getParentFile().mkdirs();
        }
        destFile.createNewFile();
        InputStream in = new FileInputStream(sourceFile);
        OutputStream out = new FileOutputStream(destFile);

        // init cipher
        Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
        Key sm4Key = new SecretKeySpec(ByteUtils.hexStrToByteArr(key), ALGORITHM_NAME);
        if (algorithmName.contains("/ECB/")) {
            cipher.init(type, sm4Key);
        } else {
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
            cipher.init(type, sm4Key, ivParameterSpec);
        }
        CipherOutputStream cout = new CipherOutputStream(out, cipher);
        byte[] cache = new byte[1024];
        int nRead = 0;
        while ((nRead = in.read(cache)) != -1) {
            cout.write(cache, 0, nRead);
            cout.flush();
        }
        cout.close();
        out.close();
        in.close();
    }

    private static byte[] sm4ByFileEn() throws NoSuchAlgorithmException, NoSuchProviderException, IOException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException {
        String sourceFilePath = "D:\\workspace\\cipherTest\\plain.txt";
        String cipherFilePath = "D:\\workspace\\cipherTest\\cipher.txt";
        byte[] key = generateKey();
        String iv = "1234567890aabcba";
        String algorithmName = "SM4/CBC/PKCS7PADDING";

        // 加密
        File sourceFile = new File(sourceFilePath);
        File destFile = new File(cipherFilePath);
        if (!sourceFile.exists() && !sourceFile.isFile()) {
            throw new IllegalArgumentException("加密源文件不存在");
        }
        if (!destFile.getParentFile().exists()) {
            destFile.getParentFile().mkdirs();
        }
        destFile.createNewFile();
        InputStream in = new FileInputStream(sourceFile);
        OutputStream out = new FileOutputStream(destFile);

        // init cipher
        Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
        Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);
        if (algorithmName.contains("/ECB/")) {
            cipher.init(Cipher.ENCRYPT_MODE, sm4Key);
        } else {
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
            cipher.init(Cipher.ENCRYPT_MODE, sm4Key, ivParameterSpec);
        }
        CipherOutputStream cout = new CipherOutputStream(out, cipher);
        byte[] cache = new byte[1024];
        int nRead = 0;
        while ((nRead = in.read(cache)) != -1) {
            cout.write(cache, 0, nRead);
            cout.flush();
        }
        cout.close();
        out.close();
        in.close();
        return key;
    }

    private static void sm4ByFileDe() throws Exception {
        String sourceFilePath = "D:\\workspace\\cipherTest\\cipher.txt";
        String decryptFilePath = "D:\\workspace\\cipherTest\\decrypt.txt";
        byte[] key = ByteUtils.hexStrToByteArr("ee970aad570e4d4ebc17f7a68e78689a");
        String iv = "1234567890aabcba";
        String algorithmName = "SM4/CBC/PKCS7PADDING";

        // 加密
        File sourceFile = new File(sourceFilePath);
        File destFile = new File(decryptFilePath);
        if (!sourceFile.exists() && !sourceFile.isFile()) {
            throw new IllegalArgumentException("加密源文件不存在");
        }
        if (!destFile.getParentFile().exists()) {
            destFile.getParentFile().mkdirs();
        }
        destFile.createNewFile();
        InputStream in = new FileInputStream(sourceFile);
        OutputStream out = new FileOutputStream(destFile);

        // init cipher
        Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
        Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);
        if (algorithmName.contains("/ECB/")) {
            cipher.init(Cipher.DECRYPT_MODE, sm4Key);
        } else {
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
            cipher.init(Cipher.DECRYPT_MODE, sm4Key, ivParameterSpec);
        }
        CipherOutputStream cout = new CipherOutputStream(out, cipher);
        byte[] cache = new byte[1024];
        int nRead = 0;
        while ((nRead = in.read(cache)) != -1) {
            cout.write(cache, 0, nRead);
            cout.flush();
        }
        cout.close();
        out.close();
        in.close();
    }
}

// pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.6.9</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.lzy</groupId>
   <artifactId>kafka-practice</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>kafka-practice</name>
   <description>kafka-practice</description>
   <properties>
      <java.version>1.8</java.version>
   </properties>
   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.kafka</groupId>
         <artifactId>spring-kafka</artifactId>
         <version>2.1.4.RELEASE</version>
      </dependency>
      <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
         <version>1.18.24</version>
      </dependency>
      <dependency>
         <groupId>com.alibaba</groupId>
         <artifactId>fastjson</artifactId>
         <version>1.2.47</version>
      </dependency>

      <!-- obs依赖 -->
      <dependency>
         <groupId>com.huaweicloud</groupId>
         <artifactId>esdk-obs-java-bundle</artifactId>
         <version>[3.21.11,)</version>
      </dependency>
      <dependency>
         <groupId>com.squareup.okhttp3</groupId>
         <artifactId>okhttp</artifactId>
         <version>4.9.3</version>
      </dependency>
      <dependency>
         <groupId>com.squareup.okio</groupId>
         <artifactId>okio</artifactId>
         <version>2.10.0</version>
      </dependency>

      <dependency>
         <groupId>com.fasterxml.jackson.core</groupId>
         <artifactId>jackson-core</artifactId>
         <version>2.13.0</version>
      </dependency>
      <dependency>
         <groupId>com.fasterxml.jackson.core</groupId>
         <artifactId>jackson-databind</artifactId>
         <version>2.13.0</version>
      </dependency>

      <!-- bouncycastle -->
      <dependency>
         <groupId>org.bouncycastle</groupId>
         <artifactId>bcprov-jdk15on</artifactId>
         <version>1.58</version>
      </dependency>

      <!-- 国密算法工具-SmUtil -->
      <dependency>
         <groupId>org.bouncycastle</groupId>
         <artifactId>bcprov-jdk15to18</artifactId>
         <version>1.66</version>
      </dependency>

   </dependencies>

   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
               <source>11</source>
               <target>11</target>
            </configuration>
         </plugin>
      </plugins>
   </build>

</project>

// ByteUtils.java

package com.lzy.util;

public class ByteUtils {
    /**
     * 将byte数组转换为表示16进制值的字符串, 如:byte[]{8,18}转换为:0813
     * @param byteArr
     * @return 转换后的字符串
     * @throws Exception
     */
    public static String byteArrToHexStr(byte[] byteArr) throws Exception {
        int iLen = byteArr.length;
        // 每个byte用两个字符才能表示,所以字符串的长度是数组长度的两倍
        StringBuffer sb = new StringBuffer(iLen * 2);
        for (int i = 0; i < iLen; i++) {
            int intTmp = byteArr[i];
            // 把负数转换为正数
            while (intTmp < 0) {
                intTmp = intTmp + 256;
            }
            // 小于0F的数需要在前面补0
            if (intTmp < 16) {
                sb.append("0");
            }
            sb.append(Integer.toString(intTmp, 16));
        }
        return sb.toString();
    }

    /**
     * 将表示16进制值的字符串转换为byte数组
     * @param hexStr  需要转换的字符串
     * @return 转换后的byte数组
     */
    public static byte[] hexStrToByteArr(String hexStr) throws Exception {
        byte[] arrB = hexStr.getBytes();
        int iLen = arrB.length;

        // 两个字符表示一个字节,所以字节数组长度是字符串长度除以2
        byte[] arrOut = new byte[iLen / 2];
        for (int i = 0; i < iLen; i = i + 2) {
            String strTmp = new String(arrB, i, 2);
            arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16);
        }
        return arrOut;
    }
}

// FileUtils.java

package com.lzy.util;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

// 参考连接: https://blog.csdn.net/jellyjiao2008/article/details/85335569
@Slf4j
public class FileUtils {
    /**
     * <p>Title: getContent</p>
     * <p>Description:根据文件路径读取文件转出byte[] </p>
     *
     * @param filePath 文件路径
     * @return 字节数组
     * @throws IOException
     */
    public static byte[] getContent(String filePath) throws IOException {
        File file = new File(filePath);
        long fileSize = file.length();
        if (fileSize > Integer.MAX_VALUE) {
            log.info("file too big...");
            return null;
        }
        FileInputStream fi = new FileInputStream(file);
        byte[] buffer = new byte[(int) fileSize];
        int offset = 0;
        int numRead = 0;
        while (offset < buffer.length
                && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) {
            offset += numRead;
        }
        // 确保所有数据均被读取
        if (offset != buffer.length) {
            throw new IOException("Could not completely read file "
                    + file.getName());
        }
        fi.close();
        return buffer;
    }

    /**
     * <p>Title: toByteArray</p>
     * <p>Description: 传统的IO流方式</p>
     *
     * @param filename
     * @return
     * @throws IOException
     */
    public static byte[] toByteArray(String filename) throws IOException {
        File file = new File(filename);
        if (!file.exists()) {
            throw new FileNotFoundException(filename);
        }
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream((int) file.length());
             BufferedInputStream in = new BufferedInputStream(new FileInputStream(file))) {
            int buf_size = 1024;
            byte[] buffer = new byte[buf_size];
            int len = 0;
            while (-1 != (len = in.read(buffer, 0, buf_size))) {
                bos.write(buffer, 0, len);
            }
            return bos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        }
    }

    /**
     * <p>Title: toByteArrayMapped</p>
     * <p>Description: 读取大文件</p>
     *
     * @param filename 文件路径
     * @return
     * @throws IOException
     */
    public static byte[] toByteArrayMapped(String filename) throws IOException {
        try (RandomAccessFile rf = new RandomAccessFile(filename, "r");
             FileChannel fc = rf.getChannel()) {
            MappedByteBuffer mappedByteBuffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()).load();
            log.info("{}", mappedByteBuffer.isLoaded());
            byte[] result = new byte[(int) fc.size()];
            if (mappedByteBuffer.remaining() > 0) {
                mappedByteBuffer.get(result, 0, mappedByteBuffer.remaining());
            }
            return result;
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        }
    }

    /**
     * 写出到文件
     * @param filePath
     * @throws Exception
     */
    public static void byteToFile(String filePath, byte[] data) throws Exception {
        Path path = Paths.get(filePath);

        // 读取、写入字节数组
//        byte[] data = Files.readAllBytes(path);
        Files.write(path, data);

    /*
        // 读取、写入字符 Since:Java11
        // 默认使用UTF-8编码读取:
        String content1 = Files.readString(path);
        // 可指定编码:
        String content2 = Files.readString(path, StandardCharsets.UTF_8);

        // 按行读取并返回每行内容:
        List<String> lines = Files.readAllLines(path);
        // 写入文本并指定编码: Since:Java11
        Files.writeString(path, "文本内容...", StandardCharsets.UTF_8);
        // 按行写入文本:
        Files.write(path, lines); */
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值