赞
踩
8大基本数据类型列表
基本类型 | 大小(字节) | 默认值 | 取值范围 | 后缀 | 示例 |
---|---|---|---|---|---|
boolean | 1 | false | {false,true} | - | boolean sign=true; |
byte | 1 | 0 | [-128,127] | - | byte b=125; |
short | 2 | 0 | [-32768~32767] | - | short num=10; |
char | 2 | ‘\u0000’ | [0,65535] | - | char ch1=‘k’; char ch2=‘\u77be’; char ch3=‘瞾’; |
int | 4 | 0 | [-2^ 31 , 2^31-1] | - | int count=100; |
long | 8 | 0 | [-2^63 , 2 ^63-1] | L/l | long a=100L; |
float | 4 | 0.0f | [-2^ 31 , 2^31-1] | F/f | float a=1.2f |
double | 8 | 0.0d | [-2^ 63,2^63-1] | D/d | double a=1.2d |
- char表示一个字符,是相对于utf-8编码而言,但是对unicode却并不是100%适用,因为有部分汉字需要4个字节(2个unicode)来表示,也就是说一个汉字字符实际上是2个char,即上表的示例
char ch3='瞾'
就不够严谨;- 我们来验证下
char ch2='\u77be';
,ch2表示1个字符,同时也可以用’\u77be’来定义,而77be
就是4个16进制位,1个16进制位表示4个二进制位(4b),则77be
表示16个二进制位(16b),即2个字节(2Byte=16bit);
InputStream
官方的注释为This abstract class is the superclass of all classes representing an input stream of bytes.
;OutputStream
官方的注释为This abstract class is the superclass of all classes representing an output stream of bytes.
public final class IoUtil { /** * 读取文件流 * <pre> * 1.文件支持从class外部读取(class调试模式)和jar内部读取(jar包使用模式) * 2.以此class是否在jar包为依据,当不在时,优先从外部读取(证明是class调试模式,根本就没有jar包) * 3.如果上述方式读不到文件,则遵从spring的读取规则(使用spring的API读取) * * @param path 文件路径 * @return 文件流 */ public static InputStream readInputStream(String path) { try { String clazzPath = IoUtil.class.getResource(FILE_SPLIT).getPath(); boolean clazzInJar = clazzPath.startsWith(FILE_TYPE); boolean inClazzWithoutJar = clazzPath.startsWith(FILE_SPLIT) && !clazzInJar; boolean inJar = path.toLowerCase(Locale.US).startsWith(CLASSPATH) || clazzInJar; String realPath = path; //非jar包模式时,拼接全路径读取 if (inClazzWithoutJar && !inJar) { if (!realPath.contains(FILE_FULL_PATH_TYPE) && !realPath.startsWith(FILE_SPLIT)) { realPath = clazzPath + realPath; } return new FileInputStream(realPath); } Resource resource = new PathMatchingResourcePatternResolver().getResource(path); boolean existFile = resource.exists(); //jar包模式运行时,通过spring的api去读取 if (existFile) { return resource.getInputStream(); } } catch (Exception e) { throw new EncryptionException("read stream error.", e); } return null; } /** * 私有化构造方法 */ private IoUtil() { } /** * 非jar形式的文件全路径标记 */ public static final String FILE_FULL_PATH_TYPE = ":"; /** * 文件类型 */ public static final String FILE_TYPE = "file:"; /** * 文件分割类型 */ public static final String FILE_SPLIT = "/"; /** * 配置类型 */ private static final String CLASSPATH = "classpath:"; }
public final class FileUtil { /** * 读取文件的二进制内容 * * @param path 文件路径 * @return 文件二进制内容 */ public static byte[] read(String path) { return read(IoUtil.readInputStream(path)); } /** * 读取输入流报文 * * @param in 文件输入流 * @return 二进制报文 */ public static byte[] read(InputStream in) { return read(in, Integer.MAX_VALUE); } /** * 读取限定文件大小的二进制流 * * @param in 二进制流 * @param size 二进制流的大小上限 * @return 文件二进制报文 */ public static byte[] read(InputStream in, int size) { try { if (size <= 0) { size = Integer.MAX_VALUE; } byte[] data = IOUtils.toByteArray(in); if (null != data && data.length > size) { LOGGER.error("failed to read limit data size:{}.", data.length); return null; } FileType fileType = FileType.getType(data); LOGGER.info("current read stream file type:{}", fileType); return data; } catch (IOException e) { LOGGER.error("failed to read input stream.", e); } finally { IOUtils.closeQuietly(in); } return null; } /** * 读取指定编码的文件内容(未指定编码格式时,则默认读取UTF-8编码) * * @param path 文件路径 * @param charset 文件编码格式 * @return 文件内容 */ public static String read(String path, Charset charset) { byte[] data = read(path); if (null == data) { LOGGER.error("failed to read input stream:{}.", path); return null; } if (null == charset) { charset = StandardCharsets.UTF_8; } return new String(data, charset); } /** * 把内容写入文件 * * @param data 二进制文件内容 * @param path 目标文件路径 */ public static void write(byte[] data, String path) { OutputStream out = null; try { File file = new File(path).getCanonicalFile(); if (!file.isFile() || !file.exists()) { FileUtils.forceMkdirParent(file); LOGGER.info("current file path[{}] force created.", file.getParentFile().getCanonicalPath()); } FileType fileType = FileType.getType(data); LOGGER.info("current write stream file type:{}", fileType); out = new FileOutputStream(file); IOUtils.write(data, out); } catch (IOException e) { LOGGER.error("failed to write file.", e); } finally { IOUtils.closeQuietly(out); } } private FileUtil() { } /** * 日志句柄 */ private static final Logger LOGGER = LoggerFactory.getLogger(FileUtil.class); }
public final class ImageUtil { /** * 从bas464中转换出图片二进制数据 * * @param base64 图片base64 * @return 图片二进制数据 */ public static byte[] toBytes(String base64) { if (StringUtils.isEmpty(base64)) { LOGGER.error("invalid base64."); return null; } try { if (base64.contains(Const.SPLIT)) { //去掉base64中的文件头前缀(如:'data:image/png;base64,') base64 = base64.substring(base64.lastIndexOf(Const.SPLIT)); } byte[] data = Base64.getMimeDecoder().decode(base64); LOGGER.info("current image file type:{}", FileType.getType(data)); return data; } catch (Exception e) { LOGGER.error("failed to get byte[] from base64.", e); } return null; } /** * 二进制图片数据转换成base64 * * @param data 图片二进制数据 * @return 图片base64 */ public static String toBase64(byte[] data) { if (null == data) { LOGGER.error("invalid image file data."); return null; } try { LOGGER.info("current image file type:{}", FileType.getType(data)); String base64 = Base64.getEncoder().encodeToString(data); if (!StringUtils.isEmpty(base64) && base64.contains(Const.SPLIT)) { //去掉base64中的文件头前缀(如:'data:image/png;base64,') base64 = base64.substring(base64.lastIndexOf(Const.SPLIT)); } return base64; } catch (Exception e) { LOGGER.error("failed to get base64 by byte[].", e); } return null; } /** * 图片文件转base64 * * @param path 文件路径 * @return 文件的base64 */ public static String toBase64(String path) { return toBase64(FileUtil.read(path)); } }
在图片场景下,Base64表示的图片字符串完全等同于图片文件;
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAjsWd3QKjDCVU+H9jkkMlOAxAKpG/nT7N+0LOQ75/SxjNaVdmLOhj
oLAtzFOnY72HoJvd62fFNllU0AkpQuotp2Ajt7W9bHfvtxS8N2EXyShSdBqr1eLo
zNwgeRqeU/uZmGVi5ehdgBTliQKeUs80mbnBwGzP6e/FUSVlXRXxyn4Pl3hclAD6
ZM3vP6vSCXIhM4LoI4c...
-----END RSA PUBLIC KEY-----
public class SecurityFacade extends BaseEncryptorFacade { /** * 本地不可逆加密或者hash * * @param data 原始数据 * @return 摘要数据 */ @Override public String hash(String data) { byte[] encBytes = this.getEncryptSecurity().hash(data.getBytes(StandardCharsets.UTF_8)); return Hex.toHexString(encBytes); } /** * 本地可逆加密 * * @param data 原始报文 * @return 加密后的报文 */ @Override public String encrypt(String data) { byte[] encBytes = this.getEncryptSecurity().encrypt(data.getBytes(StandardCharsets.UTF_8)); return Hex.toHexString(encBytes); } /** * 本地解密 * <p> * 与上面加密对应 * * @param data 加密后的数据 * @return 解密后的数据 */ @Override public String decrypt(String data) { byte[] decBytes = this.getEncryptSecurity().decrypt(Hex.decode(data)); return new String(decBytes, StandardCharsets.UTF_8); } }
魔数
。魔数
是用于识别文件格式或者协议类型的一段常量或者字符串。public enum FileType { /** * JEPG. */ JPEG("FFD8FF"), /** * PNG. */ PNG("89504E47"), /** * GIF. */ GIF("47494638"), /** * TIFF. */ TIFF("49492A00"), /** * Windows Bitmap. */ BMP("424D"), /** * CAD. */ DWG("41433130"), /** * Adobe Photoshop. */ PSD("38425053"), /** * Rich Text Format. */ RTF("7B5C727466"), /** * XML. */ XML("3C3F786D6C"), /** * HTML. */ HTML("68746D6C3E"), /** * Email [thorough only]. */ EML("44656C69766572792D646174653A"), /** * Outlook Express. */ DBX("CFAD12FEC5FD746F"), /** * Outlook (pst). */ PST("2142444E"), /** * MS Word/Excel(兼容格式). */ XLS_DOC("D0CF11E0"), /** * XLSX(excel新版本) */ XLSX("504B030414000600080000002100"), /** * DOCX(word新版本) */ DOCX("504B03041400060008000000210077"), /** * MS Access. */ MDB("5374616E64617264204A"), /** * WordPerfect. */ WPD("FF575043"), /** * Postscript. */ EPS("252150532D41646F6265"), /** * Adobe Acrobat. */ PDF("255044462D312E"), /** * Quicken. */ QDF("AC9EBD8F"), /** * Windows Password. */ PWL("E3828596"), /** * ZIP Archive. */ ZIP("504B0304"), /** * RAR Archive. */ RAR("52617221"), /** * Wave. */ WAV("57415645"), /** * AVI. */ AVI("41564920"), /** * Real Audio. */ RAM("2E7261FD"), /** * Real Media. */ RM("2E524D46"), /** * MPEG (mpg). */ MPG("000001BA"), /** * Quicktime. */ MOV("6D6F6F76"), /** * Windows Media. */ ASF("3026B2758E66CF11"), /** * MIDI. */ MID("4D546864"); /** * 获取最长的二进制文件格式对应的内容 * * @return 文件格式对应的最长的二进制长度 */ public static int getMaxBytes() { return MAX_LEN.get(); } /** * 获取文件类型 * * @param data 文件二进制 * @return 文件类型对象 */ public static FileType getType(byte[] data) { if (null == data) { LOGGER.warn("unknown file type by stream."); return null; } //1.截取最长的文件格式的二进制位数 int maxLen = Math.min(data.length, MAX_LEN.get()); byte[] suffixBytes = Arrays.copyOf(data, maxLen); //2.把最长的长度的二进制转成十六进制 String suffixTypes = Hex.toHexString(suffixBytes); for (FileType fileType : SORTED_TYPES) { if (suffixTypes.toUpperCase(Locale.US).contains(fileType.type.toUpperCase(Locale.US))) { LOGGER.info("current file type by stream:{}.", fileType.name()); return fileType; } } LOGGER.warn("unknown file type by stream."); return null; } /** * 获取到十六进制的类型 * * @return 十六进制的类型 */ public String getType() { return this.type; } @Override public String toString() { return this.name().toLowerCase(Locale.US); } /** * 构造方法 * * @param type 文件类型 */ FileType(String type) { this.type = type; } /** * 最大长度的文件二进制数位 */ private static final AtomicInteger MAX_LEN = new AtomicInteger(); /** * 排序后的文件类型集合 */ private static final List<FileType> SORTED_TYPES = Lists.newArrayList(); /** * 日志句柄 */ private static final Logger LOGGER = LoggerFactory.getLogger(FileType.class); /** * 文件类型 */ private String type; //初始化 static { //1.获取最长的文件格式的二进制长度 int maxHexLen = 0; int maxBytesLen = 0; for (FileType fileType : values()) { int len = fileType.type.length(); if (len > maxHexLen) { maxBytesLen = Hex.decode(fileType.type.getBytes(StandardCharsets.UTF_8)).length; } maxHexLen = Math.max(maxHexLen, len); } //2.把遍历的最长的二进制前缀长度保存下来 MAX_LEN.set(maxBytesLen); //3.把所有格式枚举保存起来 SORTED_TYPES.addAll(Lists.newArrayList(values())); //4.把所有的格式枚举重新排序(从长到短,为了避免文件格式存在包含而取错的情况,比如:docx格式应该包含了doc) Collections.sort(SORTED_TYPES, new Comparator<FileType>() { @Override public int compare(FileType o1, FileType o2) { return o2.type.length() - o1.type.length(); } }); } }
注意:
文件魔数
可能会存在长的16进制编码包含了短的16进制编码的情况,本逻辑判断文件格式时,会优先匹配长的16进制编码,这样就不会误判;- 为了避免大文件解析,其实并不需要解析出整个文件的二进制/十六进制内容,仅需解析大概前200个byte即可判断文件格式。
public class Sm2Encryption extends BaseSingleSignature { @Override public PublicKey toPubKey(byte[] pubKey) { try { String hexKey = Hex.toHexString(pubKey); KeyFactory kf = KeyFactory.getInstance(ALGORITHM, this.getProvider()); if (hexKey.startsWith(STANDARD_HEX_KEY_PREFIX)) { return kf.generatePublic(new X509EncodedKeySpec(pubKey)); } else { // 获取SM2相关参数 X9ECParameters ecParam = GMNamedCurves.getByName(SM2_VERSION); // 将公钥HEX字符串转换为椭圆曲线对应的点 ECCurve ecCurve = ecParam.getCurve(); ECPoint ecPoint = ecCurve.decodePoint(pubKey); // 椭圆曲线参数规格 ECParameterSpec ecSpec = new ECParameterSpec(ecCurve, ecParam.getG(), ecParam.getN(), ecParam.getH()); // 将椭圆曲线点转为公钥KEY对象 return kf.generatePublic(new ECPublicKeySpec(ecPoint, ecSpec)); } } catch (Exception e) { throw new EncryptionException("failed to get sm2 pub key.", e); } } /** * 标准的秘钥hex前缀 */ private static final String STANDARD_HEX_KEY_PREFIX = "30"; }
unicode与char的关系
结论: unicode是变长的,可以是2个字节,也可以是4个字节来表示一个字符,unicode也可以说是4/8个16进制位来表示;
GB18030-2022字符规范 正式生效在即,也有必要和大家好好分析下中文字符在UTF-8编码的Unicode规范应用;
UTF-8 unicode中文字符集 如下:
字符集 | 字数 | Unicode 编码 |
---|---|---|
基本汉字 | 20902字 | 4E00-9FA5 |
基本汉字补充 | 90字 | 9FA6-9FFF |
扩展A | 6592字 | 3400-4DBF |
扩展B | 42720字 | 20000-2A6DF |
扩展C | 4154字 | 2A700-2B739 |
扩展D | 222字 | 2B740-2B81D |
扩展E | 5762字 | 2B820-2CEA1 |
扩展F | 7473字 | 2CEB0-2EBE0 |
扩展G | 4939字 | 30000-3134A |
扩展H | 4192字 | 31350-323AF |
康熙部首 | 214字 | 2F00-2FD5 |
部首扩展 | 115字 | 2E80-2EF3 |
兼容汉字 | 472字 | F900-FAD9 |
兼容扩展 | 542字 | 2F800-2FA1D |
汉字笔画 | 36字 | 31C0-31E3 |
汉字结构 | 12字 | 2FF0-2FFB |
汉语注音 | 43字 | 3105-312F |
注音扩展 | 32字 | 31A0-31BF |
〇 | 1字 | 3007 |
public final class CharUtil { /** * 把unicode转换成字符串 * * @param ch unicode字符 * @return 字符对应的字符串显示 */ public static String fromUnicode(char[] ch) { StringBuilder result = new StringBuilder(StringUtils.EMPTY); for (char c : ch) { result.append(fromUnicode(c)); } return result.toString(); } /** * 把unicode转换成字符串 * * @param ch unicode字符 * @return 字符对应的字符串显示 */ public static String fromUnicode(char ch) { return StringUtils.EMPTY + ch; } /** * 获取范围内的连续字符集合 * * @param start 起始字符位置 * @param end 结束字符位置 * @return 字符对应的文本 */ public static List<String> fromUnicode(char[] start, char[] end) { List<String> lists = Lists.newArrayList(); char minChar = start[start.length - Const.ONE]; char maxChar = end[end.length - Const.ONE]; boolean multiUnicode = (start.length > Const.ONE); for (int index = minChar; index <= maxChar; index++) { char[] chars = {(char)index}; if (multiUnicode) { chars = new char[] {start[0], (char)index}; } String ch = CharUtil.fromUnicode(chars); lists.add(ch); } return lists; } /** * 把字符转换成unicode * * @param ch 字符 * @return 字符对应的unicode */ public static String toUnicode(String ch) { StringBuilder result = new StringBuilder(StringUtils.EMPTY); if (!StringUtils.isEmpty(ch)) { char[] chars = ch.toCharArray(); for (char c : chars) { String hex = Integer.toHexString(c); int fillLen = CHAR_HEX_LEN - hex.length(); if (fillLen > 0) { hex = StringUtils.repeat(StringUtils.EMPTY + 0, fillLen) + hex; } result.append(UNICODE_TAG).append(hex); } } return result.toString(); } /** * 是否是中文 * * @param ch 中文字符集 * @return true表示是中文 */ public static boolean isChinese(String ch) { return RegexUtil.match(ch, CHINESE_REGEX); } private CharUtil() { } /** * 一个字符对应的16进制位个数 */ private static final int CHAR_HEX_LEN = 4; /** * UNICODE起始标记 */ private static final String UNICODE_TAG = "\\u"; /** * 中文名字等字符串匹配表达式 */ private static final String CHINESE_REGEX = "^([\\u3400-\\u4dbf\\u4e00-\\u9fff\\uf900-\\ufaff\\x{20000}-\\x{323af}\\u2180-\\u2ef3\\u2f00-\\u2fd5\\u2ff0-\\u2ffb\\u3105-\\u312f\\u31a0-\\u31bf\\u31c0-\\u31e3\\u3007·])+$"; }
public class CharUtilTest { @Test public void toUnicode2() { char[] starts2 = {'\u9FA6'}; char[] ends2 = {'\u9FFF'}; toUnicode(starts2, ends2); } private void toUnicode(char[] starts, char[] ends) { List<String> chars = CharUtil.fromUnicode(starts, ends); int i = 0; for (String ch : chars) { System.out.println(String.format("[%s]%s=%s", i, ch, CharUtil.toUnicode(ch))); i++; } System.out.println("******************************************total=" + chars.size()); } }
[0]龦=\u9fa6 [1]龧=\u9fa7 [2]龨=\u9fa8 [3]龩=\u9fa9 [4]龪=\u9faa [5]龫=\u9fab [6]龬=\u9fac [7]龭=\u9fad [8]龮=\u9fae [9]龯=\u9faf [10]龰=\u9fb0 [11]龱=\u9fb1 [12]龲=\u9fb2 [13]龳=\u9fb3 [14]龴=\u9fb4 [15]龵=\u9fb5 [16]龶=\u9fb6 [17]龷=\u9fb7 [18]龸=\u9fb8 [19]龹=\u9fb9 [20]龺=\u9fba [21]龻=\u9fbb [22]龼=\u9fbc [23]龽=\u9fbd [24]龾=\u9fbe [25]龿=\u9fbf [26]鿀=\u9fc0 [27]鿁=\u9fc1 [28]鿂=\u9fc2 [29]鿃=\u9fc3 [30]鿄=\u9fc4 [31]鿅=\u9fc5 [32]鿆=\u9fc6 [33]鿇=\u9fc7 [34]鿈=\u9fc8 [35]鿉=\u9fc9 [36]鿊=\u9fca [37]鿋=\u9fcb [38]鿌=\u9fcc [39]鿍=\u9fcd [40]鿎=\u9fce [41]鿏=\u9fcf [42]鿐=\u9fd0 [43]鿑=\u9fd1 [44]鿒=\u9fd2 [45]鿓=\u9fd3 [46]鿔=\u9fd4 [47]鿕=\u9fd5 [48]鿖=\u9fd6 [49]鿗=\u9fd7 [50]鿘=\u9fd8 [51]鿙=\u9fd9 [52]鿚=\u9fda [53]鿛=\u9fdb [54]鿜=\u9fdc [55]鿝=\u9fdd [56]鿞=\u9fde [57]鿟=\u9fdf [58]鿠=\u9fe0 [59]鿡=\u9fe1 [60]鿢=\u9fe2 [61]鿣=\u9fe3 [62]鿤=\u9fe4 [63]鿥=\u9fe5 [64]鿦=\u9fe6 [65]鿧=\u9fe7 [66]鿨=\u9fe8 [67]鿩=\u9fe9 [68]鿪=\u9fea [69]鿫=\u9feb [70]鿬=\u9fec [71]鿭=\u9fed [72]鿮=\u9fee [73]鿯=\u9fef [74]鿰=\u9ff0 [75]鿱=\u9ff1 [76]鿲=\u9ff2 [77]鿳=\u9ff3 [78]鿴=\u9ff4 [79]鿵=\u9ff5 [80]鿶=\u9ff6 [81]鿷=\u9ff7 [82]鿸=\u9ff8 [83]鿹=\u9ff9 [84]鿺=\u9ffa [85]鿻=\u9ffb [86]鿼=\u9ffc [87]鿽=\u9ffd [88]鿾=\u9ffe [89]鿿=\u9fff ******************************************total=90
注意:在屏幕上能看到多少个字符,是和你的终端操作系统装的字库集有关系;
public class CharUtilTest { @Test public void fromUnicode() { char ch = '\u77be'; System.out.println(CharUtil.fromUnicode(ch) + "=" + CharUtil.toUnicode("" + ch)); } @Test public void toUnicode() { String ch = "瞾"; String format = "%s[%s]=%s=>%s"; String unicode = CharUtil.fromUnicode(ch.toCharArray()); System.out.println(String.format(format, ch, ch.toCharArray().length, CharUtil.toUnicode(ch), unicode)); String ch2 = "\uD84C\uDC7E"; String unicode2 = CharUtil.fromUnicode(ch2.toCharArray()); System.out.println(String.format(format, ch2, ch2.toCharArray().length, CharUtil.toUnicode(ch2), unicode2)); } }
瞾=\u77be
——————————————————————————————
瞾[1]=\u77be=>瞾
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/618046
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。