algoritmo LZ77 y el algoritmo de compresión Huffman basada en archivos (siete)

algoritmo LZ77 y el algoritmo de compresión Huffman basada en archivos (siete)

algoritmo de Huffman basado en la compresión de archivos y el algoritmo LZ77 (VI) se ha completado para explicar el proceso de compresión de archivos, descompresión de archivos En este artículo se explica el proceso y manejo de archivos grandes

En primer lugar, el proceso de descompresión

solución de compresión LZ77 es muy simple:

  1. Etiqueta se lee del archivo 1, y los marcadores analizados
  2. Si este indicador es 0, representa los caracteres originales, un byte es leído desde el archivo 2, archivo escrito directamente después de la descompresión
  3. Si este indicador es 1, representa encontrado (distancia, longitud de), una de dos bytes lee desde el archivo 3 representa una distancia, leer desde una longitud en bytes de un archivo, de construcción (distancia, longitud) par, a continuación, encontrar la longitud partido de los resultados Soluciones comprimidas
  4. Obtiene un siguiente marca, la marca resuelto hasta que todo terminado.

En segundo lugar, el archivo de información de la bandera de combinación y el archivo de datos comprimidos

  • Hay que descomprimir antes de que comience la fusión de archivos de datos comprimidos y el archivo de información de la etiqueta , a continuación, se fusionaron cómo distinguir entre los datos comprimidos y la información de etiqueta que ?
  • Tenemos en la compresión de archivos resultante de la fusión entre 写入标记信息的总字节数和原数据文件的大小.

Aquí Insertar imagen Descripción

  • Tenga en cuenta que después de la finalización de la fusión 文件大小和标记信息大小的 获取方式:
//获取源文件大小
  ULL fileSize = 0;
  fseek(fInF, 0 - sizeof(fileSize), SEEK_END);
  fread(&fileSize, sizeof(fileSize), 1, fInF);

  //获取标记信息的大小
  size_t flagSize = 0;
  fseek(fInF, 0 - sizeof(fileSize) - sizeof(flagSize), SEEK_END);
  fread(&flagSize, sizeof(flagSize), 1, fInF);
  • 合并文件
//合并文件
void LZ77::MergeFile(FILE* fOut, ULL fileSize) 
{
  //将压缩数据文件和标记信息文件合并
  //1.读取标记信息文件中内容,然后将结果写入到压缩文件中
  FILE* fInf = fopen("3.txt", "rb");
  size_t flagSize = 0;

  UCH* pReadbuff = new UCH[1024];
  while (true) 
  {
    size_t rdSize = fread(pReadbuff, 1, 1024, fInf);
    if (rdSize == 0)
      break;

    //把标记信息写到压缩数据文件中
    fwrite(pReadbuff, 1, rdSize, fOut);

    //更新数据
    flagSize += rdSize;
  }

  //向压缩数据文件中写标记信息大小,方便解压缩
  fwrite(&flagSize, sizeof(flagSize), 1, fOut);

  //向压缩数据文件中写文件数据大小,方便解压缩
  fwrite(&fileSize, sizeof(fileSize), 1, fOut);

  delete[] pReadbuff;
  fclose(fInf);
}
  • prestar atención读取标记信息文件指针的起始位置
 //将读取标记信息的文件指针移动到保存标记数据的起始位置
  fseek(fInF, 0 - sizeof(flagSize) - sizeof(fileSize) - flagSize, SEEK_END);
  • Tras la fusión, el proceso de descompresión:
    Aquí Insertar imagen Descripción
    Aquí Insertar imagen Descripción
    tres inicio de descompresión

  • También en el archivo de etiqueta se lee primero entre un byte chFlag (8 bits que representa los caracteres 01 bits en la longitud o la distancia original),& 0x80来判断高位01情况

  • Tenga en cuenta que si la información de bandera es 1, es representativo de la longitud de la distancia, la 长度读取出来需要 + 3.

  • Si la distancia es la longitud de la información, de nuevo se requiere un puntero a un archivo, desde 解压缩文件末尾往前偏移距离个位置(es decir, colocado para que coincida con el carácter de inicio),然后往后写长度个字符到解压缩文件

  • Nota Nota el sistema operativo con el fin de mejorar la eficiencia de la lectura del escrito, se 提供缓冲区的机制, 如果你向文件当中写入数据,其实是写到缓冲区当中,缓冲区满就才会往文件当中写mientras que hemos dicho anteriormente, el archivo descomprimido se abre con dos punteros (unos datos comprimidos se escribe, es localizar una posición de carácter correspondiente a partir ) , 现在如果写压缩数据的文件指针把数据写入到缓冲区并没有写入到文件,此时定位匹配字符开始位置的指针需要读取长度个字符写入到解压缩文件,esto va a error, ya que los datos se encuentra todavía entre el búfer de archivo comprimido, ninguno de los datos sobre el nombre del archivo comprimido, que van a leer, sólo se puede leer un 255, se llega a los efectos de la descompresión. ¿Cómo se puede solucionar? ? ?tampón de refresco

解压缩完整代码:

//解压缩
void LZ77::UNCompressFile(const std::string& strFilePath) 
{
  //打开压缩文件和标记文件
  FILE* fInD = fopen(strFilePath.c_str(), "rb");
  if (nullptr == fInD) 
  {
    std::cout << "压缩文件打开失败" << std::endl;
    return;
  }

  //操作标记数据的文件指针
  FILE* fInF = fopen(strFilePath.c_str(), "rb");
  if (nullptr == fInF) 
  {
    std::cout << "压缩文件打开失败" << std::endl;
    return;
  }

  //获取源文件大小
  ULL fileSize = 0;
  fseek(fInF, 0 - sizeof(fileSize), SEEK_END);
  fread(&fileSize, sizeof(fileSize), 1, fInF);

  //获取标记信息的大小
  size_t flagSize = 0;
  fseek(fInF, 0 - sizeof(fileSize) - sizeof(flagSize), SEEK_END);
  fread(&flagSize, sizeof(flagSize), 1, fInF);

  //将读取标记信息的文件指针移动到保存标记数据的起始位置
  fseek(fInF, 0 - sizeof(flagSize) - sizeof(fileSize) - flagSize, SEEK_END);
  //开始解压缩
  //写解压缩数据
  //FILE* ffOut = fopen("5.txt","rb");
  //std::string filestr ;
  //std::cout<<filestr<<std::endl;
  //fread(&filestr,sizeof(filestr),1,ffOut);
  //std::string str = "4.";
  //str += filestr;
  //fclose(ffOut);

  FILE* fOut = fopen("4.txt", "wb");
  assert(fOut);

  FILE* fR = fopen("4.txt", "rb");
  assert(fR);

  UCH bitCount = 0;
  UCH chFlag = 0;
  ULL encodeCount = 0;//标记已经解压缩的数据大小,方便判断解压缩的结束
  while (encodeCount < fileSize) 
  {
    //读取标记
    if (0 == bitCount) 
    {
      //读取一个字节
      chFlag=fgetc(fInF);
      bitCount = 8;
    }

    if (chFlag & 0x80)//当前字节的高位为1 
    {
      //距离长度对
      USH matchLen = fgetc(fInD) + 3;//长度
      USH matchDist = 0;//距离
      fread(&matchDist, sizeof(matchDist), 1, fInD);

      //清空缓冲区,非常重要
      fflush(fOut);

      //更新已经解码的字节数大小
      encodeCount += matchLen;

      //fR:读取前文匹配串中的内容
      UCH ch;
      fseek(fR, 0 - matchDist, SEEK_END);
      while (matchLen) 
      {
        ch = fgetc(fR);
        fputc(ch, fOut);
        --matchLen;

        //在还原长度距离对时,一定要清空缓冲区,否则可能会还原出错
        fflush(fOut);
      }
    }
    else 
    {
      //原字符
      UCH ch = fgetc(fInD);
      fputc(ch, fOut);
      encodeCount += 1;
    }

    chFlag <<= 1;
    bitCount--;
  }

  fclose(fInD);
  fclose(fInF);
  fclose(fOut);
  fclose(fR);
}

En este caso, basta con extraer los archivos han sido bien, sólo para el siguiente 大文件的压缩和解压缩suplemento

En cuarto lugar, el manejo de archivos grandes

Aquí Insertar imagen Descripción
Aquí Insertar imagen Descripción

  1. Actualización de la tabla de hash: Cuando los datos de movimiento entre la ventana derecha de la ventana izquierda, ventana de datos que se ha dejado sobrescribe, los datos ya están en la ventana derecha que empezar - lugar wsize, por lo que es necesario actualizar la tabla hash

Aquí Insertar imagen Descripción

//更新哈希表
void HashTable::Update() 
{
  for (USH i = 0; i < WSIZE; ++i) 
  {
    //先更新head,把大于等于WSIXE的下标 减去 WSIZE 放到哈希表的左窗内
    //把head中小于WSIZE 的下标直接置为0,因为小于WSIZE的下标
    //在查找缓冲区中距离先行缓冲区的距离太远了,进行匹配不划算
    if (head_[i] >= WSIZE)
      head_[i] -= WSIZE;
    else
      head_[i] = 0;

    //更新prev,和head同理
    if (prev_[i] >= WSIZE)
      prev_[i] -= WSIZE;
    else
      prev_[i] = 0;
  }
}

2. Llenar la ventana

  • Tenga en cuenta que el archivo de origen es el caso de archivos pequeños, parte entonces comprimido, no tiene ningún archivo fuente de datos, el puntero del archivo ha alcanzado el final del archivo, si la ventana de llenar los datos de nuevo a la derecha, el error será necesario que el juez

Aquí Insertar imagen Descripción

//向缓冲区中填充数据
void LZ77::FillWindow(FILE* fIn, size_t& lookAhead, USH& start) 
{
  //start压缩已经进行到右窗,先行缓冲区剩余数据不够MIN_LOOKAHEAD
  if (start >= WSIZE) //如果不进行if判断,在进行小文件压缩时还会继续
  //从文件中读取数据,但是文件已经走到末尾
  {
    //1.将右窗中的数据搬移到左窗
    memcpy(pWin_, pWin_ + WSIZE, WSIZE);

    //将右窗中的内容清0,防止影响后续数据
    memset(pWin_ + WSIZE, 0, WSIZE);

    //更新start,start本来是大于WSIZE,经过1步骤后,start应该在左窗,
    start -= WSIZEc;

    //2.更新哈希表
    ht_.Update();

    //3.向右窗中补充WSIZE个的待压缩数据
    if (!feof(fIn))//判断文件是否走到末尾
      lookAhead += fread(pWin_ + WSIZE, 1, WSIZE, fIn);
  }
}

3. Tenga en cuenta que el aspecto y la compresión de los intervalos que se solapan

  • Bajo este escenario, cuando el puntero se fue trazar BD cuando la longitud de la cadena coincidente Cuál es la distancia?(5,3)

Aquí Insertar imagen Descripción

  • 为什么指针在E4的时候不进行匹配呢? Es lógico pensar que un partido se pueden hacer. La respuesta es causada por la estructura de la tabla hash, cuando inicializar cada ubicación de la tabla hash que se establece en 0, lo que significa que coinciden con el final del partido que está alcanzando el final de la cadena, en donde, E4 BD A0 a través de cálculo de la función de hash después de que la dirección de hash, esta versión E4 carácter de subíndice entre el tampón a una dirección de hash de posición correspondiente, y esto es sólo otro índice 0, el segundo después de la llegada de E4, consigue cabeza del fósforo es 0, así que no se emparejado

Aquí Insertar imagen Descripción

  • En este caso, la reducción de la longitud requerida detampón de refresco, Es necesario para descomprimir aquí búfer de actualización dos veces
    Aquí Insertar imagen Descripción
    Aquí Insertar imagen Descripción
    Aquí Insertar imagen Descripción

Aquí Insertar imagen Descripción
Aquí Insertar imagen Descripción
Aquí Insertar imagen Descripción
Aquí se ha completado en base al algoritmo de compresión de archivos LZ77

V. Resumen

Nuestro proyecto se basa la compresión GZIP de las ideas.

1. Resumen pensamientos de compresión GZIP
Aquí Insertar imagen Descripción

2. Los artículos defectuosos

  • Presentar los Huffman y LZ77 de compresión y descompresión de algoritmos basados en archivos completados .
  • 改进的方向就是把Huffman和LZ77算法的文件压缩与解压缩结合起来,模拟GZIP
  • Pero no directamente el resultado de la compresión LZ77 comprimido con Huffman, debido a que la tasa de compresión no es lo ideal

    Aquí Insertar imagen Descripción

Aquí Insertar imagen Descripción

Aquí Insertar imagen Descripción
Aquí Insertar imagen Descripción

3. Mejora de la dirección del proyecto

  • No LZ77 compresión resultado del método de compresión directa Huffman árbol ----- árbol de Huffman modificado:范式Huffman树

4. paradigma árbol de Huffman
Ver la sección siguiente

Publicados 126 artículos originales · ganado elogios 57 · Vistas a 90000 +

Supongo que te gusta

Origin blog.csdn.net/wolfGuiDao/article/details/104787619
Recomendado
Clasificación