zlib из C ++ в C # (Как преобразовать byte [] в поток и поток в byte []) - PullRequest
6 голосов
/ 10 апреля 2009

Моя задача - распаковать пакет (полученный) с помощью zlib, а затем использовать алгоритм для создания изображения из данных

Хорошей новостью является то, что у меня есть код на C ++, но задача состоит в том, чтобы сделать это на C #

C ++

        //Read the first values of the packet received

        DWORD image[200 * 64] = {0}; //used for algoritm(width always = 200 and height always == 64)
        int imgIndex = 0; //used for algoritm
        unsigned char rawbytes_[131072] = {0}; //read below
        unsigned char * rawbytes = rawbytes_; //destrination parameter for decompression(ptr)
        compressed = r.Read<WORD>(); //the length of the compressed bytes(picture)
        uncompressed = r.Read<WORD>(); //the length that should be after decompression
        width = r.Read<WORD>(); //the width of the picture
        height = r.Read<WORD>(); //the height of the picture

        LPBYTE ptr = r.GetCurrentStream(); //the bytes(file that must be decompressed)

        outLen = uncompressed; //copy the len into another variable

        //Decompress

        if(uncompress((Bytef*)rawbytes, &outLen, ptr, compressed) != Z_OK)
        {
            printf("Could not uncompress the image code.\n");
            Disconnect();
            return;
        }

        //Algoritm to make up the picture
        // Loop through the data
        for(int c = 0; c < (int)height; ++c)
        {
            for(int r = 0; r < (int)width; ++r)
            {
                imgIndex = (height - 1 - c) * width + r;
                image[imgIndex] = 0xFF000000;
                if(-((1 << (0xFF & (r & 0x80000007))) & rawbytes[((c * width + r) >> 3)])) 
                    image[imgIndex] = 0xFFFFFFFF;
            }
        }

Я пытаюсь сделать это с zlib.NET, но все демки имеют этот код для распаковки (C #)

    private void decompressFile(string inFile, string outFile)
    {
        System.IO.FileStream outFileStream = new System.IO.FileStream(outFile, System.IO.FileMode.Create);
        zlib.ZOutputStream outZStream = new zlib.ZOutputStream(outFileStream);
        System.IO.FileStream inFileStream = new System.IO.FileStream(inFile, System.IO.FileMode.Open);          
        try
        {
            CopyStream(inFileStream, outZStream);
        }
        finally
        {
            outZStream.Close();
            outFileStream.Close();
            inFileStream.Close();
        }
    }

    public static void CopyStream(System.IO.Stream input, System.IO.Stream output)
    {
        byte[] buffer = new byte[2000];
        int len;
        while ((len = input.Read(buffer, 0, 2000)) > 0)
        {
            output.Write(buffer, 0, len);
        }
        output.Flush();
    }

Моя проблема: я не хочу сохранять файл после распаковки, потому что я должен использовать алгоритм, показанный в коде C ++.

Как преобразовать массив byte [] в поток, подобный массиву в коде C # zlib для распаковки данных, а затем как преобразовать поток обратно в байтовый массив?

Кроме того, как изменить код zlib.NET, чтобы НЕ сохранять файлы?

Ответы [ 2 ]

10 голосов
/ 10 апреля 2009

Просто используйте MemoryStreams вместо FileStreams:

// Assuming inputData is a byte[]
MemoryStream input = new MemoryStream(inputData);
MemoryStream output = new MemoryStream();

Затем вы можете использовать output.ToArray() для вывода байтового массива.

Обратите внимание, что обычно лучше использовать using операторы вместо одного блока try / finally - иначе, если первый вызов Close не удастся, остальные не будут выполнены. Вы можете вкладывать их так:

using (MemoryStream output = new MemoryStream())
using (Stream outZStream = new zlib.ZOutputStream(output))
using (Stream input = new MemoryStream(bytes))
{
    CopyStream(inFileStream, outZStream);
    return output.ToArray();
}
6 голосов
/ 02 октября 2010

Я только что столкнулся с этой же проблемой.

Для полноты ... (так как это поставило меня в тупик на несколько часов)

В случае ZLib.Net вы также должны вызвать метод finish (), который обычно происходит во время Close (), перед вызовом return output.ToArray ()

В противном случае вы получите пустой / неполный байтовый массив из вашего потока памяти, потому что ZStream еще не записал все данные:

public static void CompressData(byte[] inData, out byte[] outData)
{
    using (MemoryStream outMemoryStream = new MemoryStream())
    using (ZOutputStream outZStream = new ZOutputStream(outMemoryStream, zlibConst.Z_DEFAULT_COMPRESSION))
    using (Stream inMemoryStream = new MemoryStream(inData))
    {
        CopyStream(inMemoryStream, outZStream);
        outZStream.finish();
        outData = outMemoryStream.ToArray();
    }
}

public static void DecompressData(byte[] inData, out byte[] outData)
{
    using (MemoryStream outMemoryStream = new MemoryStream())
    using (ZOutputStream outZStream = new ZOutputStream(outMemoryStream))
    using (Stream inMemoryStream = new MemoryStream(inData))
    {
        CopyStream(inMemoryStream, outZStream);
        outZStream.finish();
        outData = outMemoryStream.ToArray();
    }
}

В этом примере я также использую пространство имен zlib:

using zlib;

Первоначально найдено в этой теме: декомпрессия ZLib

У меня недостаточно очков для голосования, поэтому ...

Спасибо Тиму Гривзу за подсказку относительно финиша перед ToArray

И Джон Скит (Jon Skeet) за подсказку о вложении операторов использования для потоков (что мне нравится гораздо лучше, чем try / finally)

...