Android移动开发-Android数据加密与解密的实现「建议收藏」

Android移动开发-Android数据加密与解密的实现「建议收藏」数据的安全是非常重要的,现在无论干什么都要账号和密码,一旦账号与密码泄露出去必将造成财产的损失,所以做好数据保密是非常重要的。Android加密算法有多种多样,常见的有MD5、RSA、AES、3DES四种。

大家好,又见面了,我是你们的朋友全栈君。

数据的安全是非常重要的,现在无论干什么都要账号和密码,一旦账号与密码泄露出去必将造成财产的损失,所以做好数据保密是非常重要的。
Android加密算法有多种多样,常见的有MD5、RSA、AES、3DES四种。

  • MD5加密:

MD5是不可逆的加密算法,也就是无法解密,主要用于客户端的用户密码加密。MD5算法加密代码如下:

  • 定义工具类MD5Util.java逻辑代码如下:
package com.fukaimei.encryptiontest.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5Util { 
   

    //首先初始化一个MessageDigest对象,该对象通过update方法获取原始数据,
    //并调用digest方法完成哈希计算,然后把字节数组逐位转换为十六进制数,最后拼装加密字符串
    public static String encrypBy(String raw) {
        String md5Str = raw;
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(raw.getBytes());
            byte[] encryContext = md.digest();

            int i;
            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < encryContext.length; offset++) {
                i = encryContext[offset];
                if (i < 0) {
                    i += 256;
                }
                if (i < 16) {
                    buf.append("0");
                }
                buf.append(Integer.toHexString(i));
            }
            md5Str = buf.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return md5Str;
    }
}

无论原始字符串是什么,MD5算法的加密串都是32位的十六进制字符串。

  • RSA加密:

RSA算法在客户端使用公钥加密,在服务端使用私钥解密。这样一来,即使加密的公钥被泄露,没有私钥仍然无法解密。(注意:使用RSA加密之前必须在AndroidStudio的libs目录下导入bcprov-jdk的jar包)RSA算法的加密代码如下:

  • 定义工具类RSAUtil.java逻辑代码如下:
package com.fukaimei.encryptiontest.util;
import com.fukaimei.encryptiontest.util.tool.ConvertBytesToBase64;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
//RSA 工具类。提供加密,解密,生成密钥对等方法。
public class RSAUtil { 

private static final String TAG = "RSAUtil";
private static final String Algorithm = "RSA";
// private static String RSAKeyStore = "E:/RSAKey.txt";
//
// //生成密钥对
// private static KeyPair generateKeyPair() throws Exception { 

// try { 

// KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(Algorithm,
// new org.bouncycastle.jce.provider.BouncyCastleProvider());
// // 这个值关系到块加密的大小,可以更改,但是不要太大,否则效率会降低
// final int KEY_SIZE = 1024;
// keyPairGen.initialize(KEY_SIZE, new SecureRandom());
// KeyPair keyPair = keyPairGen.generateKeyPair();
// saveKeyPair(keyPair);
// return keyPair;
// } catch (Exception e) { 

// throw new Exception(e.getMessage());
// }
// }
//
// private static KeyPair getKeyPair() throws Exception { 

// FileInputStream fis = new FileInputStream(RSAKeyStore);
// ObjectInputStream oos = new ObjectInputStream(fis);
// KeyPair kp = (KeyPair) oos.readObject();
// oos.close();
// fis.close();
// return kp;
// }
//
// private static void saveKeyPair(KeyPair kp) throws Exception { 

// FileOutputStream fos = new FileOutputStream(RSAKeyStore);
// ObjectOutputStream oos = new ObjectOutputStream(fos);
// oos.writeObject(kp);
// oos.close();
// fos.close();
// }
//
// //生成公钥
// private static RSAPublicKey generateRSAPublicKey(byte[] modulus,
// byte[] publicExponent) throws Exception { 

// KeyFactory keyFac = null;
// try { 

// keyFac = KeyFactory.getInstance(Algorithm,
// new org.bouncycastle.jce.provider.BouncyCastleProvider());
// } catch (NoSuchAlgorithmException ex) { 

// throw new Exception(ex.getMessage());
// }
//
// RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(
// modulus), new BigInteger(publicExponent));
// try { 

// return (RSAPublicKey) keyFac.generatePublic(pubKeySpec);
// } catch (InvalidKeySpecException ex) { 

// throw new Exception(ex.getMessage());
// }
// }
//
// //生成私钥
// private static RSAPrivateKey generateRSAPrivateKey(byte[] modulus,
// byte[] privateExponent) throws Exception { 

// KeyFactory keyFac = null;
// try { 

// keyFac = KeyFactory.getInstance(Algorithm,
// new org.bouncycastle.jce.provider.BouncyCastleProvider());
// } catch (NoSuchAlgorithmException ex) { 

// throw new Exception(ex.getMessage());
// }
//
// RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(new BigInteger(
// modulus), new BigInteger(privateExponent));
// try { 

// return (RSAPrivateKey) keyFac.generatePrivate(priKeySpec);
// } catch (InvalidKeySpecException ex) { 

// throw new Exception(ex.getMessage());
// }
// }
//
// // 通过公钥byte[]将公钥还原,适用于RSA算法
// private static PublicKey getPublicKey(byte[] keyBytes)
// throws NoSuchAlgorithmException, InvalidKeySpecException { 

// X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
// KeyFactory keyFactory = KeyFactory.getInstance(Algorithm);
// PublicKey publicKey = keyFactory.generatePublic(keySpec);
// return publicKey;
// }
//
// // 通过私钥byte[]将公钥还原,适用于RSA算法
// private static PrivateKey getPrivateKey(byte[] keyBytes)
// throws NoSuchAlgorithmException, InvalidKeySpecException { 

// PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
// KeyFactory keyFactory = KeyFactory.getInstance(Algorithm);
// PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
// return privateKey;
// }
//加密
private static byte[] encrypt(PublicKey pk, byte[] data) throws Exception {
try {
Cipher cipher = Cipher.getInstance(Algorithm,
new org.bouncycastle.jce.provider.BouncyCastleProvider());
cipher.init(Cipher.ENCRYPT_MODE, pk);
int blockSize = cipher.getBlockSize();
int outputSize = cipher.getOutputSize(data.length);
int leavedSize = data.length % blockSize;
int blocksSize = leavedSize != 0 ? data.length / blockSize + 1
: data.length / blockSize;
byte[] raw = new byte[outputSize * blocksSize];
int i = 0;
while (data.length - i * blockSize > 0) {
if (data.length - i * blockSize > blockSize) {
cipher.doFinal(data, i * blockSize, blockSize, raw, i * outputSize);
} else {
cipher.doFinal(data, i * blockSize, data.length - i * blockSize, raw, i * outputSize);
}
i++;
}
return raw;
} catch (Exception e) {
throw new Exception(e.getMessage());
}
}
//解密
private static byte[] decrypt(PrivateKey pk, byte[] raw) throws Exception {
try {
Cipher cipher = Cipher.getInstance(Algorithm,
new org.bouncycastle.jce.provider.BouncyCastleProvider());
cipher.init(cipher.DECRYPT_MODE, pk);
int blockSize = cipher.getBlockSize();
ByteArrayOutputStream bout = new ByteArrayOutputStream(64);
int j = 0;
while (raw.length - j * blockSize > 0) {
bout.write(cipher.doFinal(raw, j * blockSize, blockSize));
j++;
}
return bout.toByteArray();
} catch (Exception e) {
throw new Exception(e.getMessage());
}
}
// 使用N、e值还原公钥
private static PublicKey getPublicKey(String modulus, String publicExponent, int radix)
throws NoSuchAlgorithmException, InvalidKeySpecException {
BigInteger bigIntModulus = new BigInteger(modulus, radix);
BigInteger bigIntPrivateExponent = new BigInteger(publicExponent, radix);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(bigIntModulus,
bigIntPrivateExponent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
}
// 使用N、d值还原私钥
private static PrivateKey getPrivateKey(String modulus, String privateExponent, int radix)
throws NoSuchAlgorithmException, InvalidKeySpecException {
BigInteger bigIntModulus = new BigInteger(modulus, radix);
BigInteger bigIntPrivateExponent = new BigInteger(privateExponent, radix);
RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(bigIntModulus,
bigIntPrivateExponent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
}
//加密函数
public static String encodeRSA(RSAKeyData key_data, String src) {
if (key_data == null) {
//默认的密钥对
key_data = new RSAKeyData();
key_data.public_key = "10001";
key_data.private_key = "";
key_data.modulus = "c7f668eccc579bb75527424c21be31c104bb44c921b4788ebc82cddab5042909eaea2dd706431531392d79890f9091e13714285a7e79e9d1836397f847046ef2519c9b65022b48bf157fe409f8a42155734e65467d04ac844dfa0c2ae512517102986ba9b62d67d4c920eae40b2f11c363b218a703467d342faa81719f57e2c3";
key_data.radix = 16;
}
try {
PublicKey key = getPublicKey(key_data.modulus, key_data.public_key, key_data.radix);
String rev = encodeURL(new StringBuilder(src).reverse().toString());
byte[] en_byte = encrypt(key, rev.getBytes());
String base64 = encodeURL(ConvertBytesToBase64.BytesToBase64String(en_byte));
return base64;
} catch (Exception e) {
e.printStackTrace();
return "RSA加密失败";
}
}
//URL编码
private static String encodeURL(String str) {
String encode_str = str;
try {
encode_str = URLEncoder.encode(str, "utf-8");
} catch (Exception e) {
e.printStackTrace();
}
return encode_str;
}
//URL解码
private static String decodeURL(String str) {
String decode_str = str;
try {
decode_str = URLDecoder.decode(str, "utf-8");
} catch (Exception e) {
e.printStackTrace();
}
return decode_str;
}
public static class RSAKeyData { 

public String modulus;
public String public_key;
public String private_key;
public int radix;
public RSAKeyData() {
modulus = "";
public_key = "";
private_key = "";
radix = 0;
}
}
}

RSA算法加密结果是经过URL编码的字符串。

  • AES加密:

AES是设计用来替换DES的高级加密算法。下面是AES算法加密和解密的代码:

  • 定义工具类AesUtil.java逻辑代码如下:
package com.fukaimei.encryptiontest.util;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class AesUtil { 

private static final String Algorithm = "AES";
private final static String HEX = "0123456789ABCDEF";
//加密函数,key为密钥
public static String encrypt(String key, String src) throws Exception {
byte[] rawKey = getRawKey(key.getBytes());
byte[] result = encrypt(rawKey, src.getBytes());
return toHex(result);
}
//解密函数。key值必须和加密时的key一致
public static String decrypt(String key, String encrypted) throws Exception {
byte[] rawKey = getRawKey(key.getBytes());
byte[] enc = toByte(encrypted);
byte[] result = decrypt(rawKey, enc);
return new String(result);
}
private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
}
private static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance(Algorithm);
// SHA1PRNG 强随机种子算法, 要区别Android 4.2.2以上版本的调用方法
SecureRandom sr = null;
if (android.os.Build.VERSION.SDK_INT >= 17) {
sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
} else {
sr = SecureRandom.getInstance("SHA1PRNG");
}
sr.setSeed(seed);
kgen.init(256, sr); // 256位或128位或192位
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
}
private static byte[] encrypt(byte[] key, byte[] src) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(key, Algorithm);
Cipher cipher = Cipher.getInstance(Algorithm);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(src);
return encrypted;
}
private static byte[] decrypt(byte[] key, byte[] encrypted) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(key, Algorithm);
Cipher cipher = Cipher.getInstance(Algorithm);
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
private static byte[] toByte(String hexString) {
int len = hexString.length() / 2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++) {
result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue();
}
return result;
}
private static String toHex(byte[] buf) {
if (buf == null) {
return "";
}
StringBuffer result = new StringBuffer(2 * buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}
}

AES算法是可逆算法,支持对加密字符串进行解密,前提是解密时密钥必须与加密时一致。

  • 3DES加密:

3DES(Triple DES)是三重数据加密算法,相当于对每个数据块应用3次DES加密算法。因为原先DES算法的密钥长度过短,容易遭到暴力破解,所以3DES算法通过增加密钥的长度防范加密数据被破解。该算法的加密和解密代码如下:

  • 定义工具类Des3Util.java逻辑代码如下:
package com.fukaimei.encryptiontest.util;
import com.fukaimei.encryptiontest.util.base64.BASE64Decoder;
import com.fukaimei.encryptiontest.util.base64.BASE64Encoder;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class Des3Util { 

// 定义加密算法,DESede即3DES 
private static final String Algorithm = "DESede";
//加密函数。key为密钥
public static String encrypt(String key, String raw) {
byte[] enBytes = encryptMode(key, raw.getBytes());
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(enBytes);
}
//解密函数。key值必须和加密时的key一致
public static String decrypt(String key, String enc) {
try {
BASE64Decoder decoder = new BASE64Decoder();
byte[] enBytes = decoder.decodeBuffer(enc);
byte[] deBytes = decryptMode(key, enBytes);
return new String(deBytes);
} catch (IOException e) {
e.printStackTrace();
return enc;
}
}
private static byte[] encryptMode(String key, byte[] src) {
try {
SecretKey deskey = new SecretKeySpec(build3DesKey(key), Algorithm);
Cipher cipher = Cipher.getInstance(Algorithm);
cipher.init(Cipher.ENCRYPT_MODE, deskey);
return cipher.doFinal(src);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private static byte[] decryptMode(String key, byte[] src) {
try {
SecretKey deskey = new SecretKeySpec(build3DesKey(key), Algorithm);
Cipher cipher = Cipher.getInstance(Algorithm);
cipher.init(Cipher.DECRYPT_MODE, deskey);
return cipher.doFinal(src);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
//根据字符串生成密钥24位的字节数组
private static byte[] build3DesKey(String keyStr) throws UnsupportedEncodingException {
byte[] key = new byte[24];
byte[] temp = keyStr.getBytes("UTF-8");
if (key.length > temp.length) {
System.arraycopy(temp, 0, key, 0, temp.length);
} else {
System.arraycopy(temp, 0, key, 0, key.length);
}
return key;
}
}

3DES算法与AES一样是可逆算法,支持对加密字符串进行解密,前提是解密时密钥必须与加密时一致。

  • layout/activity_main.xml界面布局代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:focusable="true" android:focusableInTouchMode="true" android:orientation="vertical" android:padding="5dp">
<ScrollView  android:layout_width="match_parent" android:layout_height="wrap_content">
<LinearLayout  android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical">
<LinearLayout  android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal">
<TextView  android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="2" android:gravity="right" android:text="加密字符串:" android:textColor="#000000" android:textSize="16sp" />
<EditText  android:id="@+id/et_raw" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="3" android:hint="请输入要加密的字符串" android:text="" android:textColor="#000000" android:textSize="16sp" />
</LinearLayout>
<LinearLayout  android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal">
<Button  android:id="@+id/btn_md5" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="MD5加密" android:textColor="#000000" android:textSize="14sp" />
<Button  android:id="@+id/btn_rsa" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="RSA加密" android:textColor="#000000" android:textSize="14sp" />
<Button  android:id="@+id/btn_aes" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="AES加密" android:textColor="#000000" android:textSize="14sp" />
<Button  android:id="@+id/btn_3des" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="3DES加密" android:textColor="#000000" android:textSize="14sp" />
</LinearLayout>
<TextView  android:id="@+id/tv_des" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="left" android:text="" android:textColor="#000000" android:textSize="18sp" />
</LinearLayout>
</ScrollView>
</LinearLayout>
  • MainActivity.java逻辑代码如下:
package com.fukaimei.encryptiontest;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.fukaimei.encryptiontest.util.AesUtil;
import com.fukaimei.encryptiontest.util.Des3Util;
import com.fukaimei.encryptiontest.util.MD5Util;
import com.fukaimei.encryptiontest.util.RSAUtil;
public class MainActivity extends AppCompatActivity implements OnClickListener {
private final static String TAG = "MainActivity";
private EditText et_raw;
private TextView tv_des;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_raw = (EditText) findViewById(R.id.et_raw);
tv_des = (TextView) findViewById(R.id.tv_des);
findViewById(R.id.btn_md5).setOnClickListener(this);
findViewById(R.id.btn_rsa).setOnClickListener(this);
findViewById(R.id.btn_aes).setOnClickListener(this);
findViewById(R.id.btn_3des).setOnClickListener(this);
}
@Override
public void onClick(View v) {
String raw = et_raw.getText().toString();
if (raw == null || raw.length() <= 0) {
Toast.makeText(this, "请输入待加密字符串", Toast.LENGTH_LONG).show();
return;
}
if (v.getId() == R.id.btn_md5) {
String enStr = MD5Util.encrypBy(raw);
tv_des.setText("MD5的加密结果是:" + enStr);
} else if (v.getId() == R.id.btn_rsa) {
String enStr = RSAUtil.encodeRSA(null, raw);
tv_des.setText("RSA加密结果是:" + enStr);
} else if (v.getId() == R.id.btn_aes) {
try {
String seed = "a";
String enStr = AesUtil.encrypt(seed, raw);
String deStr = AesUtil.decrypt(seed, enStr);
String desc = String.format("AES加密结果是:%s\nAES解密结果是:%s", enStr, deStr);
tv_des.setText(desc);
} catch (Exception e) {
e.printStackTrace();
tv_des.setText("AES加密/解密失败");
}
} else if (v.getId() == R.id.btn_3des) {
String key = "a";
String enStr = Des3Util.encrypt(key, raw);
String deStr = Des3Util.decrypt(key, enStr);
String desc = String.format("3DES加密结果是:%s\n3DES解密结果是:%s", enStr, new String(deStr));
tv_des.setText(desc);
}
}
}
  • Demo程序运行效果界面截图如下:

MD5加密截图RSA加密截图AES加密/解密截图3DES加密/解密截图


Demo程序源码下载地址一(GitHub)
Demo程序源码下载地址二(Gitee)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/145671.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 2020年开始,中国程序员前景一片灰暗,是这样吗?[通俗易懂]

    2020年开始,中国程序员前景一片灰暗,是这样吗?[通俗易懂]背景:汇总了下老王在其他平台的原创回复,欢迎关注老王原创公众号【软件老王】,关注不迷路。1、感觉中国程序员前景一片灰暗,是这样吗?老王观点:(1)个人认为谈不上灰暗,过去十年是互联网快速爆发的十年,每个行业发展了一定程度,都会慢慢趋于平稳,软件行业也不例外。(2)其实最近也有这种感觉,感觉软件行业比以前难做了,随着政府推动的互联网+,软件行业已经进入各行各业,认为后面可能会像美国一样,成为一个基础行业,待遇和机会也会趋同于其他行业,但是不知道能不能像美国那样,到50多岁了还能写的上代码。(3

    2022年10月11日
  • Unix/Linux环境C编程新手教程(22) C/C++怎样获取程序的执行时间「建议收藏」

    Unix/Linux环境C编程新手教程(22) C/C++怎样获取程序的执行时间

  • mac版ps快捷键大全示意图_苹果电脑ps选中图片快捷键是什么

    mac版ps快捷键大全示意图_苹果电脑ps选中图片快捷键是什么psmac快捷键1、打开文件-Command+O2、创建文档-Command+N3、放大和缩小-Command+加号或减号4、存储为Web格式-Command+Option+Shift+S5、转换层-转化的活性层发生时按Command+T6、自定义快捷键-Option+Command+Shift+K7、首选项-Command+K8、色阶–Command+L9、曲线-Command+M10、色相/饱和度–C

  • allure command

    allure commandallure-Usage:allure[options][command][commandoptions]Options:–helpPrintcommandlinehelp.-q,–quietSwitchonthequietmode.Default:false-v,–verboseSwitchontheverbosemode.Default:false…

  • python线性回归算法「建议收藏」

    python线性回归算法「建议收藏」1.线性回归算法2.在Python中实现线性回归那我们如何在Python中实现呢?利⽤Python强⼤的数据分析⼯具来处理数据。Numpy提供了数组功能,以及对数据进⾏快速处理的函数。Numpy还是很多⾼级扩展库的依赖,⽐如Pandas,Scikit_Learn等都依赖于它。Scikit_Learn扩展库,这是⼀个机器学习相关的库。它提供了完善的机器学习⼯具箱,包括数据预处理、分类、回归、预测等。2.1安装sklearn⼯具本⾸先进⼊到虚拟环境cd~/Desktop/env_s

  • 阅读UML类图和时序图

    阅读UML类图和时序图

    2021年12月31日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号