Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

Bytes dentro do Buffer ao usar a função GetString

Quando não usa a sobrecarga da função GetString, ela repete caracteres que ficaram armazenados no buffer, porém como que é feito esse armazenamento na prática ? Como que fica salvo ? ele não tinha que limar tudo quando "reseta" para incluir os bytes no buffer definido, mesmo que sobre espaço disponíveis ?

Estou com o seguinte código:

        var enderecoDoArquivo = "contas.txt";
        using (var fluxoDoArquivo = new FileStream(enderecoDoArquivo, FileMode.Open))
        {
            var buffer = new byte[1024]; // 1kb
            var numeroDeBytesLidos = -1;

            while (numeroDeBytesLidos != 0)
            {
                numeroDeBytesLidos = fluxoDoArquivo.Read(buffer, 0, 1024);
                EscreverBuffer(buffer, numeroDeBytesLidos);

            }

            Console.ReadLine();
        }

    }
    static void EscreverBuffer(byte[] buffer, int bytesLidos)
    {
        var utf8 = Encoding.Default;


        var texto = utf8.GetString(buffer, 0, bytesLidos);
        Console.Write(texto);
    }
2 respostas
solução!

Ele não deveria limpar.

Primeiramente vamos entender como funciona o GetString apenas com o array de bytes como parâmetro. Nesse caso ele vai tentar ler o array de bytes inteiro.

byte[] buffer = new byte[] { 99, 100, 101 };
string text = Encoding.UTF8.GetString(buffer);

A variável text retornará "cde".

Mas na verdade, a questão principal aqui não é o GetString. Ele apenas converte para string o array de bytes. A questão toda é: Por que seu array de bytes não é limpo?

Primeiro vamos entender um pouco do funcionamento do Stream. Ele mantém um offset interno para saber qual a posição do byte que precisa ler. Conforme você vai lendo o Stream, esse offset vai aumentando. Então ele começa desse offset e lê uma certa quantidade de bytes.

Essa "certa quantidade de bytes" dependerá de:

Se o buffer for menor ou igual do que falta ser lido, então essa certa quantidade será o tamanho do buffer; Se o buffer for maior do que falta ser lido, então essa certa quantidade será o que falta ser lido.

Repare que você está caindo nessa segunda condição.

Então vamos considerar a seguinte condição:

Você possui um arquivo de 10 bytes para ler. Você criou um buffer de 6 bytes. Então:

Na primeira vez que ler o stream, ele lerá os primeiros 6 bytes. Na segunda vez que ler o stream, ele lerá os próximos 4 bytes.

Um exemplo:

Seu arquivo possui os seguintes bytes: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] Seu buffer só foi instanciando, então ele está com os seguintes bytes: [0, 0, 0, 0, 0, 0]

Após a primeira leitura, seu buffer ficará: [1, 2, 3, 4, 5, 6] Após a segunda leitura, o stream verificará que está no offset 7 e começará a partir dali apontando inicialmente pro index 0 do seu array de bytes. ficando assim: [7, 8, 9, 10, 5, 6].

Repare que ninguém limpou o seu byte. O papel do stream é simplesmente preencher os bytes. Como seu buffer já estava preenchido da primeira iteração, ele preencheu o que precisava e pronto. Até por isso ele retorna a quantidade de bytes que foram lidos, para ser possível saber até onde o buffer foi preenchido nessa iteração e pegar só aquela parte.

Esse exemplo simula a situação acima:

byte[] file = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
byte[] buffer = new byte[6];
using Stream stream = new MemoryStream(file);

int read;

while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
    Console.WriteLine(string.Join(',', buffer));

Você verá que no Console será mostrado: 1,2,3,4,5,6 7,8,9,10,5,6

Perfeito amigo, eu tinha minhas dúvidas se era em pilha, mas depois dessa explicação ficou tudo muito claro. Agradeço muito.