速度之王 — LZ4压缩算法(二)

2023-05-16

LZ4 (Extremely Fast Compression algorithm)

项目:http://code.google.com/p/lz4/

作者:Yann Collet

本文作者:zhangskd @ csdn blog

 

LZ4格式

 

The compressed block is composed of sequences.

每个数据块可以压缩成若干个序列,格式如下:

 

 

(1) literals

length of literals. If it is 0, then there is no literal. If it is 15, then we need to add some more bytes to indicate the

full length. Each additional byte then represent a value of 0 to 255, which is added to the previous value to produce

a total length. When the byte value is 255, another byte is output.

literals are uncompressed bytes, to be copied as-is.

 

(2) match

offset. It represents the position of the match to be copied from.

Note that 0 is an invalid value, never used. 1 means "current position - 1 byte".

The maximum offset value is really 65535. The value is stored using "little endian" format.

matchlength. There is an baselength to apply, which is the minimum length of a match called minmatch.

This minimum is 4. As a consequence, a value of 0 means a match length of 4 bytes, and a value of 15 means a

match length of 19+ bytes. (Similar to literal length)

 

(3) rules

1. The last 5 bytes are always literals.

2. The last match cannot start within the last 12 bytes.

So a file within less than 13 bytes can only be represented as literals.

 

(4) scan strategy

a single-cell wide hash table.

Each position in the input data block gets "hashed", using the first 4 bytes (minimatch). Then the position is stored

at the hashed position. Obviously, the smaller the table, the more collisions we get, reducing compression

effectiveness. The decoder do not care of the method used to find matches, and requires no addtional memory.

 

(5) Streaming format

 

实现

 

(1) 哈希表

Each position in the input data block gets "hashed", using the first 4 bytes (minimatch). Then the position is stored

at the hashed position. Obviously, the smaller the table, the more collisions we get, reducing compression

effectiveness. The decoder do not care of the method used to find matches, and requires no addtional memory.

 

LZ4使用哈希表来查找匹配字符串。这个哈希表的映射关系(key, value):

key为4个字节的二进制值。

value为这4个字节在块中的位置。

/* Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache。
 * Increasing memory usage improves compression ratio
 * Reduced memory usage can improve speed, due to cache effect
 */

#define MEMORY_USAGE 14
#define LZ4_HASHLOG (MEMORY_USAGE - 2) /* 哈希桶位数12 */
#define HASHTABLESIZE (1 << MEMORY_USAGE) /* 哈希表大小2^14 = 16K */
#define HASHNBCELLS4 (1 << LZ4_HASHLOG) /* 哈希桶个数2^12 = 4K */

 

选择哈希表的大小时,要做一个权衡:

1. 侧重压缩比,则哈希表可以大一些。

2. 侧重压缩速度,则哈希表应该适中,以便能装入L1 cache。

默认的哈希表使用的内存为16KB,能装进L1 cache,这也是LZ4压缩速度快的一个原因。

当前主流的Intel X86 L1 Data Cache为32KB,所以建议哈希表不要超过此大小。

 

typedef enum { byPtr, byU32, byU16} tableType_t;

哈希表存储的数据为“位置”,分三种情况:

1. inputSize小于64KB时,使用byU16,表示16位的偏移值即可。

2. inputSize大于64KB时:

    2.1 指针大小为8字节,使用byU32,表示32位的偏移值,如果用指针不划算。

    2.2 指针大小为4字节,使用byPtr,表示32位的指针。

 

采用整数哈希算法。

2654435761U是2到2^32的黄金分割素数,2654435761 / 4294967296 = 0.618033987。

计算哈希值,输入为4个字节,输出可分为2字节值、4字节值两种哈希值。

FORCE_INLINE int LZ4_hashSequence(U32 sequence, tableType_t tableType)
{
    if (tableType == byU16)
        /* 哈希表为16K,如果哈希value为16位 => 哈希key为13位 */
        return (((sequence) * 2654435761U) >> ((MINMATCH * 8) - (LZ4_HASHLOG + 1)));
    else
        /* 哈希表为16K,如果哈希value为32位 => 哈希key为12位 */
        return (((sequence) * 2654435761U) >> ((MINMATCH * 8) - LZ4_HASHLOG));
}

FORCE_INLINE int LZ4_hashPosition(const BYTE *p, tableType_t tableType) \
    { return LZ4_hashSequence(A32(p), tableType); }

把地址存入到哈希表中。

FORCE_INLINE void LZ4_putPositionOnHash(const BYTE *p, U32 h, void *tableBase, tableType_t tableType,
       const BYTE *srcBase)
{
    switch(tableType)
    {
    case byPtr: { const BYTE **hashTable = (const BYTE **) tableBase; hashTable[h] = p; break; }
    case byU32: { U32 *hashTable = (U32 *) tableBase; hashTable[h] = (U32) (p - srcBase); break; }
    case byU16: { U16 *hashTable = (U16 *) tableBase; hashTable[h] = (U16) (p - srcBase); break; }
    }
}

计算指针p指向的4字节的哈希值,然后把它的位置存入哈希表中。

FORCE_INLINE void LZ4_putPosition(const BYTE *p, void *tableBase, tableType_t tableType, const BYTE *srcBase)
{
    U32 h = LZ4_hashPosition(p, tableType); /* 计算哈希值 */
    LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); /* 把地址存入哈希表 */
}

根据哈希值,获取地址。

FORCE_INLINE const BYTE *LZ4_getPositionOnHash(U32 h, void *tableBase, tableType_t tableType,
    const BYTE *srcBase)
{
    if (tableType == byPtr) { const BYTE **hashTable = (const BYTE **) tableBase; return hashTable[h]; }
    if (tableType == byU32) { U32 *hashTable = (U32 *) tableBase; return hashTable[h] + srcBase; }
    { U16 *hashTable = (U16 *) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */
}

根据指针p指向的4字节,计算哈希值,并查找此哈希桶是否已有赋值。

如果此哈希桶已有赋值,则说明此时的4字节和上次的4字节很可能是一样的(如果是冲突,则是不一样的)。

FORCE_INLINE const BYTE *LZ4_getPosition(const BYTE *p, void *tableBase, tableType, const BYTE *srcBase)
{
    U32 h = LZ4_hashPosition(p, tableType);
    return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase);
}

 

(2) 压缩

LZ4_compress()是压缩的一个入口函数,先申请哈希表,然后调用LZ4_compress_generic()。

/* LZ4_compress():
 * Compress inputSize bytes from source into dest.
 * Destination buffer must be already allocated, and must be sized to handle worst cases situations
 * (input data not compressible)
 * Worst case size evaluation is provided by function LZ4_compressBound()
 * inputSize: Max support value is LZ4_MAX_INPUT_VALUE
 * return: the number of bytes written in buffer dest or 0 if the compression fails.
 */

int LZ4_compress(const char *source, char *dest, int inputSize)
{
#if (HEAPMODE) /* 在堆中给哈希表分配内存 */
    void *ctx = ALLOCATOR(HASHNBCELLS4, 4); /* Aligned on 4-bytes boundaries */
#else /* 在栈中给哈希表分配内存,比较快,默认 */
    U32 ctx[1U << (MEMORY_USAGE - 2) ] = {0}; /* Ensure data is aligned on 4-bytes boundaries */
#endif
    int result;

    /* 输入小于64K+11,则用16位来表示滑动窗口,否则用32位*/
    if (inputSize < (int) LZ4_64KLIMIT) 
        result = LZ4_compress_generic((void *)ctx, source, dest, inputSize, 0, notLimited, byU16, noPrefix);
    else
        result = LZ4_compress_generic((void *)ctx, source, dest, inputSize, 0, notLimited,
                            (sizeof(void *) == 8 ? byU32 : byPtr, noPrefix);

#if (HEAPMODE)
    FREE(ctx);
#endif
    return result;
}
#define MINMATCH 4 /* 以4字节为单位查找哈希表 */
#define COPYLENGTH 8 
#define LASTLITERALS 5
#define MFLIMIT (COPYLENGTH + MINMATCH) /* 对于最后的12个字节,不进行查找匹配 */
const int LZ4_minLength = (MFLIMIT + 1); /* 一个块要>=13个字符,才会进行查找匹配 */
#define LZ4_64KLIMIT ((1<<16) + (MFLIMIT - 1)) /* 64K + 11 */
/* Increasing this value will make the compression run slower on incompressible data。
 * 用于控制查找匹配时的前进幅度,如果一直没找到匹配,则加大前进幅度。
 */
#define SKIPSTRENGTH 6

 

LZ4_compress_generic()是主要的压缩函数,根据指定的参数,可以执行多种不同的压缩方案。

 

匹配算法

1. 当前的地址为ip,它的哈希值为h。

2. 下个地址为forwardIp,它的哈希值为forwardH (下个循环赋值给ip、h)。

3. 按照哈希值h,获取哈希表中的值ref。

    3.1 ref为初始值,没有匹配,A32(ip) != A32(ref),继续。

    3.2 ref不为初始值,有匹配。

          3.2.1 ref不在滑动窗口内,放弃,继续。

          3.2.2 ref对应的U32和ip对应的U32不一样,是冲突,继续。

          3.3.3 ref在滑动窗口内,且对应的U32一样,找到了match,退出。

4. 保存ip和h的对应关系。

FORCE_INLINE int LZ4_compress_generic(void *ctx, const char *source, char *dest, int inputSize,
        int maxOutputSize, limitedOutput_directive limitedOutput, tableType_t tableType, 
        prefix64k_directive prefix)
{
    const BYTE *ip = (const BYTE *) source;
    /* 用作哈希表中的srcBase */
    const BYTE *const base = (prefix == withPrefix) ? ((LZ4_Data_Structure *)ctx)->base : (const BYTE *)source);
    /* 前向窗口的起始地址 */
    const BYTE *const lowLimit = ((prefix == withPrefix) ? ((LZ4_Data_Structure *)ctx)->bufferStart : (const BYTE *)source);
    const BYTE *anchor = (const BYTE *)source;
    const BYTE *const iend = ip + inputSize; /* 输入的结束地址 */
    const BYTE *const mflimit = iend - MFLIMIT; /* iend - 12,超过此处不允许再启动一次匹配 */
    const BYTE *const matchlimit = iend - LASTLITERALS; /* iend - 5,最后5个字符不允许匹配 */

    BYTE *op = (BYTE *) dest; /* 用于操作输出缓存 */
    BYTE *const oend = op + maxOutputSize; /* 输出缓存的边界,如果有的话 */

    int length;
    const int skipStrength = SKIPSTRENGTH; /* 6 */
    U32 forwardH;

    /* Init conditions */
    if ((U32) inputSize > (U32) LZ4_MAX_INPUT_SIZE) return 0; /* 输入长度过大 */
    /* must continue from end of previous block */
    if ((prefix == withPrefix) && (ip != ((LZ4_Data_Structure *)ctx)->nextBlock)) return 0;
    /* do it now, due to potential early exit. 保存下一个块的起始地址 */
    if (prefix == withPrefix) ((LZ4_Data_Structure *)ctx)->nextBlock = iend;
    if ((tableType == byU16) && (inputSize >= LZ4_64KLIMIT)) return 0; /* Size too large (not within 64K limit) */
    if (inputSize < LZ4_minlength) goto _last_literals; /* 如果输入长度小于13,则不查找匹配 */
    
    /* First Byte */
    LZ4_putPosition(ip, ctx, tableType, base); /* 计算以第一个字节开头的U32的哈希值,保存其位置 */
    ip++; forwardH = LZ4_hashPosition(ip, tableType); /* 计算以第二个字节开头的U32的哈希值 */

    /* Main loop,每次循环查找一个匹配,产生一个序列 */
    for ( ; ; )
    {
        int findMatchAttempts = (1U << skipStrength) + 3;
        const BYTE *forwardIp = ip;
        const BYTE *ref;
        BYTE *token;

        /* Find a match,查找一个匹配,或者到了尽头mflimit */
        do {
            U32 h = forwardH; /* 当前ip对应的哈希值 */
            int step = findMatchAttempts++ >> skipStrength; /* forwardIp的偏移,一般是1 */
            ip = forwardIp;
            forwardIp = ip + step; /* 前向缓存中下个将检查的地址 */
            
            if unlikely(forwardIp > mflimit) { goto _last_literals; } /* >=12字节才会去匹配 */
            forwardH = LZ4_hashPosition(forwardIp, tableType); /* forwardIp的哈希值 */ 

            /* 这里是查找的关键:按照哈希值h,获取地址ref。
             * 1. 没有匹配,ref为srcBase。
             * 2. 有匹配。
             *     2.1 不在滑动窗口内,继续。
             *     2.2 对应的U32不一样,是冲突,继续。
             *     2.3 在滑动窗口内,且对应的U32一样,找到了match,退出。
             */ 
            ref = LZ4_getPositionOnHash(h, ctx, tableType, base); 
            LZ4_putPositionOnHash(ip, h, ctx, tableType, base); /* 保存ip、h这个对应关系 */
        } while ((ref + MAX_DISTANCE < ip) || (A32(ref) != A32(ip)));
 
        /* 找到匹配之后,看能否向前扩大匹配 */
        while((ip > anchor) && (ref > lowLimit) && unlikely(ip[-1] == ref[-1])) { ip--; ref--; }
       
        /* Encode Literal length,赋值Literal length */
        length = (int) (ip - anchor);
        token = op++;

        /* Check output limit */
        if ((limitedOutput) & unlikely(op + length + 2 + (1 + LASTLITERALS) + (length>>8) > oend)) return 0;

        if (length >= (int) RUN_MASK) {
            int len = length - RUN_MASK;
            *token = (RUN_MASK << ML_BITS);
            for(; len >= 255; len -= 255) *op++ = 255;
            *op++ = (BYTE) len;
        } else
            *token = (BYTE) (length << ML_BITS);

        /* Copy Literals,复制不可编码字符 */
        { BYTE * end = (op) + (length); LZ4_WILDCOPY(op, anchor, end); op = end; }

_next_match: /* 向后扩展匹配 */
        /* Encode Offset,赋值offset,op += 2 */
        LZ4_WRITE_LITTLEENDIAN_16(op, (U16) (ip - ref));

        /* Start Counting */
        ip += MINMATCH; ref += MINMATCH; /* MinMatch already verified */
        anchor = ip;

        while likely(ip < matchlimit - (STEPSIZE - 1)) {
            size_t diff = AARCH(ref) ^ AARCH(ip); /* 异或,值为零表示相同 */
            if (! diff) { ip += STEPSIZE; ref += STEPSIZE; continue; }
            ip += LZ4_NbCommonBytes(diff); /* STEPSIZE不同,看其中有多少个字节是相同的 */
            goto _endCount;
        }

        if (LZ4_ARCH64) 
            if ((ip < (matchlimit - 3)) && (A32(ref) == A32(ip))) { ip += 4; ref += 4; }
        if ((ip < matchlimit - 1)) && (A16(ref) == A16(ip))) { ip += 2; ref += 2; }
        if ((ip < matchlimit) && (*ref == *ip)) ip++;

_endCount:
        /* Ecode MatchLength,赋值match length */
        length = (int) (ip - anchor);
        /* Check output limit */
        if ((limitedOutput) && unlikely(op + (1 + LASTLITERALS) + (length >> 8) > oend)) return 0;

        if (length >= (int) ML_MASK) {
            *token += ML_MASK;
            length -= ML_MASK;
            for (; length > 509; length -= 510) { *op++ = 255; *op++ = 255; }
            if (length >= 255) { length -= 255; *op++ = 255; }
            *op++ = (BYTE) (length);
        } else
            *token += (BYTE) (length);

        /* Test end of chunk */
        if (ip > mflimit) { anchor = ip; break; } /* 不再进行匹配了 */
        /* Fill table,顺便保存 */
        LZ4_putPosition(ip - 2, ctx, tableType, base);   

        /* Test next position,尝试着找匹配 */
        ref = LZ4_getPosition(ip, ctx, tableType, base);
        LZ4_putPosition(ip, ctx, tableType, base);
        /* 如果找到匹配,说明没有literals,可以直接跳过查找、赋值literal length */
        if ((ref + MAX_DISTANCE >= ip) && (A32(ref) == A32(ip))) { token = op++; *token = 0; goto _next_match; }   

        /* Prepare next loop,准备进行下个循环 */
        anchor = ip++;
        forwardH = LZ4_hashPosition(ip, tableType);
    }

_last_literals:
    /* Encode Last Literals */
    {
        int lastRun = (int) (iend - anchor); /* 最后原字符串长度 */

        if ((limitedOutput) && (((char *)op - dest) + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > 
                (U32) maxOutputSize))
            return 0; /* check output limit */

        if (lastRun >= (int) RUN_MASK) { 
            *op ++ = (RUN_MASK << ML_BITS); 
            lastRun -= RUN_MASK;
            for (; lastRun >= 255; lastRun -=255) *op++ = 255;
            *op++ = (BYTE) lastRun;
        } else
            *op++ = (BYTE) (lastRun << ML_BITS);

        memcpy(op, anchor, iend - anchor); /* 复制literals */
        op += iend - anchor;
    }
 
    /* End */
    return (int) (((char *)op) - dest); /* 返回压缩后的长度 */
}

#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */
#define ML_BITS 4 /* Token: 4-low-bits, match length */
#define ML_MASK ((1U << ML_BITS) - 1)
#define RUN_BITS (8 - ML_BITS) /* Token: 4-high-bits, literal length */
#define RUN_MASK ((1U << RUN_BITS) - 1)

#define MAXD_LOG 16 /* 滑动窗口的位数 */
#define MAX_DISTANCE ((1 << MAXD_LOG) - 1) /* 滑动窗口的最大值 */


 

转载于:https://www.cnblogs.com/aiwz/p/6333316.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

速度之王 — LZ4压缩算法(二) 的相关文章

  • go sqlite mysql_Go实战--go语言操作sqlite数据库(The way to go)

    生命不止 xff0c 继续 go go go 继续与大家分享 xff0c go语言的实战 xff0c 今天介绍的是如何操作sqlite数据库 何为sqlite3 xff1f SQLite is a self contained high r
  • mysql+join+合计_解决MySQL左联LIFT JOIN做求和数据出现重复数据。

    SELECT GROUP CONCAT DISTINCT fa nickname GROUP CONCAT DISTINCT ev facility id CONVERT SUM ev income DECIMAL 10 2 AS su C
  • 在debian纯字符界面安装vmware tools或者VirtualBox的增强功能开启共享文件夹

    1 检查有没有安装gcc和make 可以通过which gcc或者whereis gcc查看 再检查make sudo apt get install gcc make 2 安装内核头文件 内核头文件默认是会安装到 usr src目录下 如
  • “远程调试监视器(MSVSMON.EXE)似乎没有在远程计算机上运行“的完美解决方案

    今天调试程序时 xff0c Visual Studio突然报出了如下错误 xff1a Microsoft Visual Studio 远程调试监视器 MSVSMON EXE 似乎没有在远程计算机上运行 这可能是因为防火墙阻止与远程计算机通信
  • Go——切片困惑

    1 数组 Go的数组是有固定个相同类型元素的数据结构 xff0c 底层采用连续的内存空间存放 xff0c 数组一旦声明后大小就不可改变了 注意 xff1a Go中的数组是一种基本类型 xff0c 数组的类型不仅包括其元素类型 xff0c 也
  • Tensorflow版本和python对应关系,以及tensorflow下载路径

    A few installation mechanisms require the URL of the TensorFlow Python package The value you specify depends on your Pyt
  • windows下 go安装qt绑定

    1 下载安装QT 离线版QT地址 https download qt io official releases qt 5 11 5 11 1 qt opensource windows x86 5 11 1 exe 注意 xff1a 最好全
  • ios设备备份,更新路径(mac os)

    备份路径 xff1a Library Application Support MobileSync Backup 固件更新下载路径 xff1a Library iTunes iPhone Software Updates 转载于 https
  • Flutter FormatException: Bad UTF-8 encoding 0xc3 (at offset 172)

    是文件编码问题 1 xff0c 打开 Android Studio 进入设置界面 Ctrl 43 Alt 43 S 或 File gt Settings 打开如下界面 xff1a 2 xff0c 将 Project Encodeing 设置
  • 数据库系统原理及应用教程复习笔记(第3 版)

    最近在复习数据库相关知识点 xff0c 过几天就要考试了 xff1b 第一章 数据库基础知识 1 数据库管理是数据处理的基础工作 xff0c 数据库是数据管理的技术和手段 数据库中的数据具有整体性和共享性 1 2 数据库系统的核心 xff1
  • ubuntu 由于没有公钥,无法验证下列签名

    W GPG 错误 xff1a http deb opera com stable InRelease 由于没有公钥 xff0c 无法验证下列签名 xff1a NO PUBKEY 63F7D4AFF6D61D45 没有公钥的此类错误只要在终端
  • mysql2 没有配置文件怎么办

    1111mysql没有配置文件会用默认的配置 启动时没有使用配置文件 如果没有设置使用指定目录my cnf文件及默认读取目录没有my cnf文件 xff0c 表示mysql启动时并没有加载配置文件 xff0c 而是使用默认配置 需要修改配置
  • repo init 时gpg: 无法检查签名:找不到公钥

    i found a solution here http www marshut com wrrts repo release 1 12 4 html Sorry I realized today that we didn 39 t upl
  • 使用Java对字符串进行升序排序

    Java对字符串的很多API和功能是JavaWeb能广泛发展的基础 xff0c 下面是一道经典的字符串操作题 xff0c 需要边查JAVASE的API对每个步骤进行操作 题目 xff1a 给一个字符串 xff0c 34 34 12 8 0
  • 2.2 关系代数运算

    2 2 1 关系代数的五个基本操作 考核要求 xff1a 达到 简单应用 层次 知识点 xff1a 五个基本操作的含义和运算应用 1 并 xff1a 两个关系需有相同的关系模式 xff0c 并的对象是元组 xff0c 由两个关系所有元组构成
  • FTP 之 550 permission denied

    做案子時 將WinInet dll封裝 用C 調用 做了四個函數 分別是上傳 下載 刪除 清空文件夾 在開發環境中測試沒有任何問題 但拿到正式環境中卻出現 34 550 c dh MPF dir ABC 34 不存在的錯誤 但實際上的FTP
  • Go——值、指针和引用

    传值还是传引用 在函数和接口章节 xff0c 我们知道Go只有一种参数传递规则 xff0c 那就是值拷贝 xff0c 这种规则包括两种含义 xff1a 函数参数传递时使用的是值拷贝 实例赋值给接口变量 xff0c 接口对实例的引用是值拷贝
  • 读取PC版微信数据库(电脑版微信数据库)内容

    原始网址 https www cnblogs com Charltsing p WeChatPCdb html 联系QQ xff1a 564955427 1 PC版微信的密钥是32位byte xff0c 不同于安卓版 xff08 7位字符串
  • Pytorch-属性统计

    引言 本篇介绍Pytorch属性统计的几种方式 统计属性 求值或位置 normmean sumprodmax min argmin argmaxkthvalue topk norm norm 与 normalize norm指的是范数 xf
  • 高性能异步爬虫

    背景 其实爬虫的本质就是client发请求批量获取server的响应数据 xff0c 如果我们有多个url待爬取 xff0c 只用一个线程且采用串行的方式执行 xff0c 那只能等待爬取一个结束后才能继续下一个 xff0c 效率会非常低 需

随机推荐

  • [operator]deepin 卸载自带搜狗输入法后,输入法消失

    解决这个问题我先是升级了官方的im config套件 xff0c 升级后发现并没有什么用 xff0c 然后使用以下方式 xff0c 做个记录 命令行操作 删除搜狗的残留文件 cd config rm rf SogouPY users rm
  • DPK

    一 概念 dpk文件是Delphi的包文件 xff0c 有dpk文件的组件安装比较方便 一般来说 xff0c 支持不同版本Delphi的组件会有不同的dpk文件 xff0c 一般以7结尾的dpk文件是支持Delphi 7的 如果没有支持De
  • free -g 说明

    free g 说明 xff1a free g 43 buffers cache 说明 xff1a buffer 写缓存 xff0c 表示脏数据写入磁盘之前缓存一段时间 xff0c 可以释放 sync命令可以把buffer强制写入硬盘 cac
  • Google Drive 里的文件下载的方法

    Google Drive 里并不提供创建直接下载链接的选项 xff0c 但是可以通过小小的更改链接形式就能把分享的内容保存到本地 例如 xff0c 一份通过 Google Drive 分享的文件链接形式为 xff1a https drive
  • 关于虚拟机VMware Tools安装中出现的无法自动安装VMCI驱动程序的问题

    问题 解决方法 根据配置文件信息找到所在的虚拟机位置 找到后缀名为vmx的文件 xff0c 右键打开方式中选择使用记事本打开 选择左上角编辑中的查找功能输入图中的查找内容后 xff0c 点击查找下一个 将其原先的TRUE值改为false即可
  • 服务器系统运行内存,服务器系统运行内存使用情况

    服务器系统运行内存使用情况 内容精选 换一换 包年 包月的计费模式也称为包周期计费模式 xff0c 是一种预付费方式 xff0c 按订单的购买周期计费 xff0c 适用于可预估资源使用周期的场景 xff0c 价格比按需计费模式更优惠 包年
  • Ubuntu 18.04 上使用xrdp远程桌面登录蓝屏解决

    所有工具方法来自 http c nergy be blog p 61 13663 免责声明 xff1a 像往常一样 xff0c 使用此风险自负 xff01 本地有台机器装了乌班图18 04版本系统 我们想远程图形化访问它 我第一想法是xrd
  • Go——习惯用法

    1 干净与强迫症 Go在代码干净上有了近乎苛刻的要求 xff0c 主要体现在如下几个方面 xff1a 编译器不能通过未使用的局部变量 xff08 包括未使用的标签 xff09 import 未使用的包同样通不过编译 所有的控制结构 函数和方
  • snprintf()函数使用方法

    众所周知 sprintf不能检查目标字符串的长度 xff0c 可能造成众多安全问题 所以都会推荐使用snprintf 自从snprintf代替了sprintf xff0c 相信大家对snprintf的使用都不会少 xff0c 函数定义如下
  • Openwrt无线中继设置并访问外网

    Openwrt无线中继设置并访问外网 本篇博文参考来自 xff1a http blog csdn net pifangsione article details 13162023 配置目标 主路由器使用AP模式发射Wifi从路由器使用Cli
  • 在 Windows 7 中禁用IPv6协议/IPv6隧道

    How to disable certain Internet Protocol version 6 IPv6 components in Windows Vista Windows 7 and Windows Server 2008 ht
  • python matplotlib绘图大全(散点图、柱状图、饼图、极坐标图、热量图、三维图以及热图)...

    2019 7 14晚 matplotlib七种常见图像输出编程大全 七种图形汇总输出如下 xff1a import numpy as np 导入数据结构nmupy模块 import matplotlib pyplot as plt 导入ma
  • 光纤模式分布 matlab,matlab计算单模光纤模式分布(公布源代码及参考文献)

    最近在使用matlab计算单模光纤纤芯模及包层模模场分布时 xff0c 有一些问题一直悬而未决 xff0c 多次咨询原作者后虽解决了部分问题 xff0c 但是余下的问题原作者也不理我了 xff0c 特发此贴以广交学习光纤方面的同学 老师及科
  • Ubuntu下编译安装MySQL5.7

    tar zxvf mysql 5 7 14 tar gz cd mysql 5 7 14 第一步 xff1a cmake DCMAKE INSTALL PREFIX 61 usr local mysql DMYSQL DATADIR 61
  • UNICODE使用的一些知识和技巧

    UNICODE宏和 UNICODE宏的关系 在windows编程中 经常要编译Unicode版本的程序 方法是工程文件的配置中加上UNICODE或者 UNICODE编译条件 那么到底是用哪一个呢 Jeffrey Richter在 Windo
  • cmake 常用命令

    1 使用日期 获取时间 string TIMESTAMP DATE TIME 34 y m d H M 34 获取日期 string TIMESTAMP DATE VERSION 34 m d 34 转载于 https www cnblog
  • QQ2008 msg.db,user.db读取

    Saturday November 27 2010 msg db读取 下载 user db读取 下载 转载于 https www cnblogs com ycdx2001 archive 2010 11 27 1889498 html
  • MongoDB——Mac环境搭建

    1 下载 官网地址 xff1a https www mongodb com 2 解压并配置 解压到 usr local 配置Path xff0c vim打开 bash profile添加export PATH 61 PATH usr loc
  • Django模型

    模型是你的数据的唯一的 权威的信息源 它包含你所储存数据的必要字段和行为 通常 xff0c 每个模型对应数据库中唯一的一张表 1 基础 每个模型都是django db models Model 的一个Python 子类 模型的每个属性都表示
  • 速度之王 — LZ4压缩算法(二)

    LZ4 Extremely Fast Compression algorithm 项目 xff1a http code google com p lz4 作者 xff1a Yann Collet 本文作者 xff1a zhangskd 64