Mit LZF Byte Array komprimieren

  • C#

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von VincentTB.

    Mit LZF Byte Array komprimieren

    Hallo,
    ich benötige einen schnellen Koprimierungsalgorithmus, um Pakete vor dem Verschicken über einen TCP Client etwas zu verkleinern. Ursprünglich hatte ich mir dafür QuickLZ ausgesucht, welche folgende statischen Methoden aufweist:

    C#-Quellcode

    1. public static byte[] Compress(byte[] source, uint start, uint size)
    2. public static byte[] Decompress(byte[] source, uint start)


    Nun habe ich mir den LZF Algorithmus ausgesucht, welcher sehr ähnlich von der Geschwindigkeit her sein soll. Jedoch verwirren mich jetzt die Signaturen der Methoden: (Quelle)

    C#-Quellcode

    1. /// <summary>
    2. /// Compresses the data using LibLZF algorithm
    3. /// </summary>
    4. /// <param name="input">Reference to the data to compress</param>
    5. /// <param name="inputLength">Lenght of the data to compress</param>
    6. /// <param name="output">Reference to a buffer which will contain the compressed data</param>
    7. /// <param name="outputLength">Lenght of the compression buffer (should be bigger than the input buffer)</param>
    8. /// <returns>The size of the compressed archive in the output buffer</returns>
    9. public int Compress(byte[] input, int inputLength, byte[] output, int outputLength)
    10. /// <summary>
    11. /// Decompresses the data using LibLZF algorithm
    12. /// </summary>
    13. /// <param name="input">Reference to the data to decompress</param>
    14. /// <param name="inputLength">Lenght of the data to decompress</param>
    15. /// <param name="output">Reference to a buffer which will contain the decompressed data</param>
    16. /// <param name="outputLength">The size of the decompressed archive in the output buffer</param>
    17. /// <returns>Returns decompressed size</returns>
    18. public int Decompress(byte[] input, int inputLength, byte[] output, int outputLength)



    Als erstes fehlt mir, dass ich bestimmen kann, ab wann er denn eigentlich komprimieren soll. Zweitens verwirrt mich, dass ich einen Buffer angeben soll. Soll ich jetzt schätzen, wie groß es nachher wird?! Wie soll ich das denn schätzen? Mit QuickLZ habe ich die Erfahrung gemacht, dass es manchmal nach dem Komprimieren wesentlich größer war als vorher, aber manchmal auch wesentlich kleiner. Wie soll das denn funktionieren, ohne dass da dauernd eine Exception ausgelöst werden kann? Und wieso soll ich ihm sagen, wie groß der angegebene Buffer ist, obwohl er das doch selber einfach gucken kann.


    Wäre schön, wenn mir mal hier jemand auf die Sprünge helfen kann :)
    Mfg
    Vincent

    Hi,
    hab mal in den Code geschaut. Ich denke der Zweck der OutputSize ist, einen Maximalwert anzugeben, wenn der überschritten wird bekommst du 0 zurück. Notfalls setzt du es auf MaxValue oder du entfernst es ganz und entfernst auch die entsprechenden 3 Checks aus der .cs. Ich kann mich täuschen :D. Beim OutputBuffer würde ich einfach mal die selbe Size wie für den InputBuffer verwenden und schauen obs klappt. Ich kenne den Algo nicht, aber eigentlich sollte es ja kleiner werden.

    Grüße
    "Life isn't about winning the race. Life is about finishing the race and how many people we can help finish the race." ~Marc Mero

    Nun bin ich also auch soweit: Keine VB-Fragen per PM! Es gibt hier ein Forum, verdammt!
    Der Autor der library nutzt in seinen Benchmarks folgenden Code:

    C#-Quellcode

    1. static byte[] LzfCompress(byte[] data) {
    2. var output = new byte[data.Length * 2];
    3. var size = lzf.Compress(data, data.Length, output, output.Length);
    4. return output;
    5. }
    6. static byte[] LzfDecompress(byte[] data) {
    7. var output = new byte[data.Length * 2];
    8. lzf.Decompress(data, data.Length, output, output.Length);
    9. return output;
    10. }
    sieht mir ziemlich dusslig aus, das Design.
    Weil output ist doch ein Array, und ein Array weiß doch seine Länge selber. Ist doch Schwwachsinn, dann die Array-Länge zusätzlich noch mit angeben zu müssen.

    Bei solchen Autoren wär ich skeptisch, zumindest, solange das nach Unfug aussieht - vlt. gibts ja einen Grund, aber der Grund kann auch sein, dass der Autor nicht sonderlich kompetent ist.

    Edit: ok - es ist eine (schludrige) C-Portierung, das ist der Grund. Portierungs-Mängel sind imo nicht soo besorgniserregend, wer C schlecht nach c# portiert kann deshalb trotzdem ein ausgezeichneter c-Progger sein.
    Nur halt schade sowas - wie man sieht, sorgt es für ziemliche Irritation.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()

    ErfinderDesRades schrieb:

    Bei solchen Autoren wär ich skeptisch, zumindest, solange das nach Unfug aussieht - vlt. gibts ja einen Grund, aber der Grund kann auch sein, dass der Autor nicht sonderlich kompetent ist.
    In diesem Fall liegt das daran, dass es sich um eine leicht verbesserte Version der Portierung aus C der LibLZF handelt. Wenn du dir die Original-Signatur der Funktion ansiehst, bemerkst du sicher die Analogie:

    C-Quellcode

    1. ​unsigned int
    2. lzf_compress (const void *const in_data, unsigned int in_len,
    3. void *out_data, unsigned int out_len)
    Jo. Ist etwas unglücklich geportet, weil Du in .NET dafür halt Enumerable-Klassen mit Längen- bzw. Anzahl-Properties hast. In C arbeitet er da mit Pointern und da muss natürlich klar sein, wie oft man den inkrementieren soll, um im Speicher weiter die einzelnen Elemente zu lesen und keine Access Violation auszulösen (Wäre in C++ übrigens auch so, wenn man bspw. mit Iteratoren arbeitet).
    Das Ganze müsste man daher halt etwas C# bzw. .NET-konformer abändern, um diese Redundanz loszuwerden. Im Groben und Ganzen spielt das aber ja keine Rolle in der Auswirkung auf den Grundalgorithmus, daher kann man dem schon vertrauen, würde ich sagen.

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    Aber wieso in aller Welt muss ich dann jedes Mal die doppelte Größe an Speicherplatz reservieren?! Gut, die meisten Pakete sind eher kleiner (also unter 1000 Bytes), aber es kann auch schonmal sein, dass da 5 MB verschickt werden. Und dann kommt ja noch der Framework Overhead dazu. Frechheit, und dann muss ich alle Daten nochmal kopieren, weil man nicht die Startbytes angeben kann und die Prefix Bytes somit entfernt werden müssen, also für ein 5 MB Paket brauche ich dann über 30 MB (5 MB empfangen, 5 MB um den Prefix zu entfernen (damit dekomprimiert werden kann), 10 MB Buffer, 5 MB das Ergebnis und Framework Overhead).

    Das erscheint mir höchst ungünstig, dafür, dass QuickLZ das mit 10 MB schafft, da lohnt sich das komprimieren ja kaum noch...

    Trotzdem Danke an alle Antworten, zur Not muss ich das halt ein bisschen umschreiben :D
    Mfg
    Vincent