計算機的血肉:數據

爲何計算機是基於二進制的

最先人們出現了大量計算的需求,首先經歷了人工算而後藉助算盤再到步進計算器、差分機、分析機。 計算的需求變得愈來愈大,機器也愈來愈先進,首先由於數學家能夠經過邏輯運算進行加減乘除等邏輯運算,而後人們發明了機械繼電器來描述狀態表述二進制,因爲機械的東西故障率很高又經歷了熱電子管(真空管)-> 晶體管、計算機便開始了快速發展,二進制也成爲現代計算機的數據承載標準。html

自從分析機出現後這些計算工具開始了初步編程化,而後出現了打孔機。直到出現馮·諾依曼結構,計算機開始蓬勃發展。java

進制轉換

先說一下各個進制的通常的表述方式git

進制名稱 Java 中寫法 通常表示符號
二進制 0b101 0b 開頭是二進制 BIN
八進制 011 0 開頭是八進制 OCT
十進制 11 正常數字寫法就是十進制 DEC
十六進制 0x11 0x 開頭是十六進制 HEX

你們可使用如下語句輸出一下看看具體值是多少。算法

System.out.println(0b101);
System.out.println(011);
System.out.println(11);
System.out.println(0x11);
複製代碼

二進制與十進制

二進制到十進制:10100 = 1 * 2^4 + 0 * 2^3 + 1 * 2^2 + 0 * 2^1 + 0 * 2^0 = 20
複製代碼

十進制到二進制:
20 / 2 = 10 餘 0
10 / 2 = 5 餘 0
5 / 2 = 2 餘 1
2 / 2 = 1 餘 0
1 / 2 = 0 餘 1

把餘數倒序:10100
複製代碼

八進制與十進制

八進制到十進制:12345 = 1 * 8^4 + 2 * 8^3 + 3 * 8^2 + 4 * 8^1 + 5 * 8^0 = 5349
複製代碼

十進制到八進制:
5349 / 8 = 668 餘 5
668 / 8 = 83 餘 4
83 / 8 = 10 餘 3
10 / 8 = 1 餘 2
1 / 8 = 0 餘 1

把餘數倒序:12345
複製代碼

十六進制與十進制

十六進制到十進制:123BF = 1 * 16^4 + 2 * 16^3 + 3 * 16^2 + B(11) * 16^1 + F(15) * 16^0 = 74687
複製代碼

十進制到十六進制:
74687 / 16 = 4667 餘 F(15)
4667 / 16 = 291 餘 B(11)
291 / 16 = 18 餘 3
18 / 16 = 1 餘 2
1 / 16 = 0 餘 1

把餘數倒序:123BF
複製代碼

字符編碼

本質是根據標準存儲十進制索引編號。 哈夫曼最小字符編碼(五位 32個值)-> Ascll 編碼(7位 128個值) -> Unicode 編碼(16位)編程

UTF-8 與 Unicode 的區別

你們看一看阮一峯大神寫的這一篇便可。數組

字符編碼筆記:ASCII,Unicode 和 UTF-8bash

Base64 原理

首先咱們瞭解一下 Base64 是什麼?最初網絡傳輸有不少特殊字符服務器沒法識別,傳輸起來有些問題,因此發明 Base64 編碼來進行轉碼。服務器

Base64 是使用大小寫英文字母各26個、數字10個、加號 + 和斜槓 / 64 個字符來表示數據的編碼,除了有以上 64 個符號,還有一個 = 做爲後綴。由於只有 64 個有效字符,因此二進制有效位也只有 6 位(00111111 能夠表示 64 個數)。網絡

Base64 索引表

由於此處咱們是轉碼文本,因此文本轉換二進制是經過 Ascll 碼錶來轉換的,而後每 6 位轉換爲十進制,而後根據十進制查詢 Base64 索引表查詢相應字符進行拼接,最後使用 = 表明 6 位去補齊,使位的總長度爲 8 的倍數。解碼亦如此。app

Base64 的原理看到了,咱們能夠戳破幾個不正確的說法。

  1. Base64 加密算法,咱們看到了這根本不是什麼加密算法,只是編碼算法而已,最多使內容不能讓人一眼就能記住。
  2. Base64 壓縮,壓縮也是不對的方法,根據他的實現方式,咱們基本能夠算出通過 Base64 編碼會使數據增大 1/3。若是是對 Base64 編碼後的數據在進行壓縮,那就是其餘壓縮方式了,就不屬於 Base64 編碼的範疇了。

byte[] 與 十六進制字符串 轉換

public static String toHex(byte[] bytes) {
    if (bytes == null) {
        return "";
    }
    final char[] hexArray = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
    // byte 最大值是 255 轉成字符串則爲 0xFF,因此字符串長度是 byte 數組的兩倍。
    char[] hexChars = new char[bytes.length * 2];
    int v;
    for (int j = 0; j < bytes.length; j++) {
        v = bytes[j] & 0xFF; // 取 8 個位
        hexChars[j * 2] = hexArray[v >>> 4]; // 取高 4 位放入 char
        hexChars[j * 2 + 1] = hexArray[v & 0x0F]; // 取低 4 位放入 char
    }
    return new String(hexChars); // 轉換爲字符串
}
複製代碼
public static byte[] fromHex(String s) {
        if (s != null) {
            try {
                StringBuilder sb = new StringBuilder(s.length());
                for (int i = 0; i < s.length(); i++) {
                    char ch = s.charAt(i);
                    // 首先把空格 '\n' '\r' 等特殊字符排除掉
                    if (!Character.isWhitespace(ch)) {
                        sb.append(ch);
                    }
                }
                s = sb.toString();
                int len = s.length();
                // 緣由已經解釋過了 byte 數組是字符串長度的 1/2
                byte[] data = new byte[len / 2];
                for (int i = 0; i < len; i += 2) {
                    // 將 char 轉換爲 int 當作高 4 位
                    int hi = (Character.digit(s.charAt(i), 16) << 4);
                    // 將 char 轉換爲 int 當作低 4 位
                    int low = Character.digit(s.charAt(i + 1), 16);
                    if (hi >= 256 || low < 0 || low >= 16) {
                        return null;
                    }
                    // 經過位運算合併
                    data[i / 2] = (byte) (hi | low);
                }
                return data;
            } catch (Exception ignored) {
            }
        }
        return null;
    }
複製代碼

這個字符串轉換 byte 很差理解咱們畫張圖,來輔助理解下。

媒體編碼

全部媒體都是同樣的,規範一個媒體格式爲表述標準,而後使用相應格式的解析器來解析。

壓縮

壓縮在咱們平常生活中很常見,通常都是對二進制數據進行壓縮,咱們今天爲了簡單就用簡單的字符串舉例來說明。

無損壓縮

假如文字內容是:你好啊你好你好你好你好你好你好你好你好你好你好

簡單定義一個壓縮方法,壓縮以後就是:1*你好啊,10*你好

經過咱們自定義的算法解壓縮就能夠還原了,通常公司的壓縮算法都是比較複雜的。

有損壓縮

咱們如今使用的聲音文件存儲的都是聲音波形。

假設有個聲音文件:12 -32 45 23 -54 0 -7 34 37 89 -23 0 -54

有損壓縮就是經過某些算法把某些無用的波形刪掉,再執行無損壓縮,可是解碼回來就會少一部分聲音。這就是有損壓縮。

至於那些波形是無用的,是不少科學家,數學家研究得知。

編程語言基本類型(以 Java 爲例)

類型 字節
boolean 1 8
byte 1 8
char 2 16
short 2 16
int 4 32
long 8 64
float 4 32
double 8 64

計算機中最小的傳遞單位就是 1 字節,通常使用 byte 來承載。咱們在通常的開發中確定會遇到這種在流中讀取數據或字節數組轉換成其餘類型或在字節中讀取相應位的數據等等業務場景,好比網絡傳輸,藍牙設備或物聯網設備交互的場景,可能都會遇到。我舉兩個高位在前,低位在後的例子,這類操做通常都是使用位運算來實現。你們在業務中遇到其餘的場景隨機應變便可。

byte 與 char 的轉換(高位在前,低位在後)

char c1 = '中'; // 二進制 0100111000101101 UTF-8 編碼爲 ’中‘

byte[] bytes = new byte[2];
bytes[0] = (byte) ((c1 >> 8) & 0xff); // 01001110
bytes[1] = (byte) (c1 & 0xff); // 00101101

char c2 = '國'; // 二進制 0100111000101101 UTF-8 編碼爲 '國'
// 第一步先把 c2 的值清空,兩種方式
// 1. 左移 16 位將 c2 清零
c2 = (char) (c2 << 16);

// 2. 無符號右移 16 位將 c2 清零
c2 = (char) (c2 >>> 16);

c2 = (char) (c2 | (bytes[0] & 0XFF)); // 將低八位賦值
c2 = (char) ((c2 << 8) | (bytes[1] & 0XFF)); // 左移八位,繼續將低八位賦值

// c2 的值被改成 ’中‘
複製代碼

byte 與 int 的轉換(高位在前,低位在後)

int i1 = 1234567890; // 二進制 01001001 10010110 00000010 11010010
byte[] bytes = new byte[4];
bytes[0] = (byte) ((i1 >> 24) & 0xFF);
bytes[1] = (byte) ((i1 >> 16) & 0xFF);
bytes[2] = (byte) ((i1 >> 8) & 0xFF);
bytes[3] = (byte) (i1 & 0xFF);


int i2 = 0;
i2 = i2 | (bytes[0] & 0XFF);
i2 = (i2 << 8) | (bytes[1] & 0XFF);
i2 = (i2 << 8) | (bytes[2] & 0XFF);
i2 = (i2 << 8) | (bytes[3] & 0XFF);
複製代碼

取 Int 中的其中幾位

在咱們通常的物聯網通訊中可能會在一個 short 值中把操做符和 data 都放進去。好比一個 short 是 2 字節。也就是 16 位,舉個例子好比前四位表示操做符,中間8位表示數據,後四位表示校驗位。

假設與設備通信中規定好收到兩個字節。

// byte[] 轉換成 short
short data = 0;
data = (short) (data | (bytes[0] & 0XFF));
data = (short) ((data << 8) | (bytes[1] & 0XFF)); 

//假設 data 十進制的值爲 31766 ,二進制爲 01111100 00010110
// 取得前四位操做符 operator 爲 28672 二進制 0111 0000 0000 0000
short operator = (short) (data & 0xF000); // 0xF000:11110000 00000000

// 取得中間八位數據 data1 爲 3088 二進制 0000 1100 0001 0000
short data1 = (short) (data & 0x0FF0); // 0x0FF0:00001111 11110000

// 取得後四位校驗位 check 爲 6 二進制 0000 0000 0000 0110
short check = (short) (data & 0x000F); // 0x000F:00000000 00001111

複製代碼

高位,低位

假設有個二進制的值爲 1001 0110。

高位是左邊開始數,好比高四位就是 1001。

低位是右邊開始數,好比低四位就是 0110。

小結

這一篇我講的比較亂,可是魂並無散,講的都是二進制層面的一些知識點,也許不是最經常使用的也不是最全面的,可是若是我這篇博客,你可以看明白能夠受益不淺。

相關文章
相關標籤/搜索