C# - Calculando o CRC de strings e arquivos
O CRC - Cyclic redundancy check, ou verificação de redundância cíclica é um código detector de erros cujo algoritmo é muito usado em protocolos de comunicação diferentes, empacotamento e desempacotamento de algoritmos para garantir a robustez dos dados.
A idéia por trás do CRC é simples - calcular um checksum original (seqüência de verificação de quadros) para cada quadro de dados, baseada em seu conteúdo e colar o checksum no final de cada mensagem. Uma vez que os dados são recebidos, é possível realizar o mesmo cálculo e comparar os resultados - se os resultados são semelhantes, a mensagem é válida.
O CRC é calculado e anexado na informação a transmitir (ou armazenar) sendo verificado após a recepção ou acesso, para confirmar se não ocorreram alterações
O CRC é popular por ser simples de implementar em hardware binário, simples de ser analisado matematicamente, e pela eficiência em detectar erros típicos causados por ruído em canais de transmissão.
A utilidade do CRC advém das
seguintes propriedades:
1. Como todos os bits são usados no cálculo do CRC, a mudança
em apenas um bit provoca uma mudança no CRC.
2. Mesmo mudanças pequenas nos dados levam a CRCs muito
diferentes. Experiências com o CRC-32 (usando polinômios de
32 bits) mostram que é muito raro que a introdução de
erros nos dados não seja detectado pelo CRC.
3. A probabilidade de qualquer dos 232 valores possíveis para o
CRC é praticamente uniforme.
Existem diferentes tipos de CRC que podem ser calculados: CRC-32, CRC-16, CRC-12, CRC-8, etc.
Para realizarmos cálculos
envolvendo o CRC temos que utilizar o namespace
System.Security.Cryptography
e neste artigo eu ou calcular o CRC de
strings e arquivos.
Vamos abrir o Visual C# 2010 Express Edition e no menu File-> New Poject, selecione o Template Windows Forms Applicacion com o nome Calculando_CRC;
No menu Project -> Add Class inclua uma classe com o nome CrcStream com o seguinte código:
using System.IO; namespace Macoratti { /// <summary> /// Encapsula um <see cref="System.IO.Stream" /> para calcular o checksum CRC32 /// em tempo de execução /// </summary> public class CrcStream : Stream { /// <summary> /// Encapsula um <see cref="System.IO.Stream" />. /// </summary> /// <param name="stream">O stream para calcular o checksum.</param> public CrcStream(Stream stream) { this.stream = stream; } Stream stream; /// <summary> /// Obtem o stream. /// </summary> public Stream Stream { get { return stream; } } public override bool CanRead { get { return stream.CanRead; } } public override bool CanSeek { get { return stream.CanSeek; } } public override bool CanWrite { get { return stream.CanWrite; } } public override void Flush() { stream.Flush(); } public override long Length { get { return stream.Length; } } public override long Position { get { return stream.Position; } set { stream.Position = value; } } public override long Seek(long offset, SeekOrigin origin) { return stream.Seek(offset, origin); } public override void SetLength(long value) { stream.SetLength(value); } public override int Read(byte[] buffer, int offset, int count) { count = stream.Read(buffer, offset, count); readCrc = CalculateCrc(readCrc, buffer, offset, count); return count; } public override void Write(byte[] buffer, int offset, int count) { stream.Write(buffer, offset, count); writeCrc = CalculateCrc(writeCrc, buffer, offset, count); } uint CalculateCrc(uint crc, byte[] buffer, int offset, int count) { unchecked { for (int i = offset, end = offset + count; i < end; i++) crc = (crc >> 8) ^ table[(crc ^ buffer[i]) & 0xFF]; } return crc; } static private uint[] table = GenerateTable(); static private uint[] GenerateTable() { unchecked { uint[] table = new uint[256]; uint crc; const uint poly = 0xEDB88320; for (uint i = 0; i < table.Length; i++) { crc = i; for (int j = 8; j > 0; j--) { if ((crc & 1) == 1) crc = (crc >> 1) ^ poly; else crc >>= 1; } table[i] = crc; } return table; } } uint readCrc = unchecked(0xFFFFFFFF); /// <summary> /// Obtem o checksum CRC dos dados que foram lidos pelo stream /// </summary> public uint ReadCrc { get { return unchecked(readCrc ^ 0xFFFFFFFF); } } uint writeCrc = unchecked(0xFFFFFFFF); /// <summary> /// Obtem o checksum CRC dos dados que foram escritos para o stream /// </summary> public uint WriteCrc { get { return unchecked(writeCrc ^ 0xFFFFFFFF); } } /// <summary> /// Reseta a leitura e escrita dos checksums. /// </summary> public void ResetChecksum() { readCrc = unchecked(0xFFFFFFFF); writeCrc = unchecked(0xFFFFFFFF); } } } autor : http://www.codeproject.com/Members/reinux |
Agora vamos definir no formulário form1.cs uma interface bem simples onde iremos informar o nome do arquivo e calcular o seu CRC.
Abaixo vemos o formulário que usa os controles TextBox e Button;
No evento Click do botão de comando - Calcula CRC - vamos incluir o código que usa a classe CrcStream para calcular o CRC do arquivo:
using System; using System.Windows.Forms; using System.IO; using Macoratti; namespace Calculando_CRC { public partial class Form1 : Form { public Form1() { InitializeComponent(); } FileStream file = null; CrcStream stream = null; private void btnCalculaCRC_Click(object sender, EventArgs e) { if (txtArquivo.Text == string.Empty) { MessageBox.Show("Informe o nome do arquivo."); return; } string arquivo = txtArquivo.Text; //Abre um fluxo de stream e o encapsula em um CrcStream try { file = new FileStream(arquivo, FileMode.Open); stream = new CrcStream(file); } catch (Exception ex) { MessageBox.Show("Erro ao acessar o arquivo : " + ex.Message); return; } //Usa o arquivo - neste caso le o arquivo como uma string StreamReader reader = new StreamReader(stream); string texto = reader.ReadToEnd(); //Imprime o checksum calculado txtCRC.Text = stream.ReadCrc.ToString("X8"); } } } |
Executando o projeto iremos obter para um determinado arquivo informado:
Pegue o projeto completo aqui: Calculando_CRC.zip
Romanos 2:2
E bem sabemos que o juízo de Deus é segundo a verdade, contra os que tais coisas praticam.Referências: