Strings als Container für Rohdaten "missbrauchen"



  • Fast alle Programmiersprachen haben irgendeine String-Implementation, eine Klasse, Arrays eines speziellen Datentyps für lesbare Zeichen. Dabei sind noch allerlei Kodierungen und Kompressionsverfahren wie UTF-8, Codepages, Locales, 16-Bit Unicode einer speziellen Endianess, usw, die zu allem Überfluss auch noch automatisch zuschlagen.

    Normalerweise ist es eine sehr schlechte Idee, sowas für Binärdaten zu nutzen. Trotzdem: was ist am besten, wenn man das machen will? Ich denke, man wandelt seine Rohdaten in Base64 um. Oder gibt es einen besseren Trick?



  • Warum nicht einfach Binärdaten schreiben, wenn diese auch gemeint sind?


  • Global Moderator |  Mod

    @john-0 sagte in Strings als Container für Rohdaten "missbrauchen":

    Warum nicht einfach Binärdaten schreiben, wenn diese auch gemeint sind?

    Das hier. Fast alle Programmiersprachen haben irgendeine Implementierung für Binärdaten, eine Klasse, Arrays eines unspeziellen Datentyps für nicht-lesbare Zeichen.



  • Solange deine Bytes ebenfalls 8 Bit haben, kannst du in den std::string alles reinkippen, was du willst. Ich hab das Ding auch schon als Basis für einen SocketPuffer benutzt, weil es eigentlich nicht viel mehr als ein eleganter Wrapper um ein char* ist und ich mir so auf elegante Art und Weise ein new und ein delete spare.
    Mit data() kriegst du auch das const char* raus und wenn du drauf rum wurschteln willst, kannst du dir ja das const wegcasten 😎 😎 😎
    ( solange die Länge des Strings konstant bleibt. data() wird ungültig sobald sich die size ändert. )

    Von irgendwelchen Interpretationen oder Automatismen die greifen könnten und dir deine Daten versauen, ist mir nichts bekannt.



  • @SeppJ sagte in Strings als Container für Rohdaten "missbrauchen":

    Das hier. Fast alle Programmiersprachen haben irgendeine Implementierung für Binärdaten, eine Klasse, Arrays eines unspeziellen Datentyps für nicht-lesbare Zeichen.

    Dafür darf man sich mit mit std::string mit anderen Problemen herumschlagen, ob es sich um signed oder unsigned char handelt. Zudem ist std::string ein Container für Zeichen, und somit bietet er Funktionalität die gar nicht für dieses Ziel sinnvoll ist. Weshalb nicht std::vector<unsigend char> ?



  • @RBS2 sagte in Strings als Container für Rohdaten "missbrauchen":

    Ich denke, man wandelt seine Rohdaten in Base64 um. Oder gibt es einen besseren Trick?

    Kommt immer auf die Anforderungen an. Grundsätzlich gilt was die anderen schon geschrieben haben, also idealerweise keine Strings verwenden wenn man BLOBs abspeichern will. Wenn du aber nen guten Grund hast warum du die BLOBs in String-Objekten speichern/transportieren willst, dann sollte man diesen guten Grund kennen bevor man antwortet. Bzw. einfach die genaueren Umstände.

    Base64 ist z.B. ein guter Mix aus kompakt und performant. Hex ist schneller dafür nicht so kompakt. Und wieder andere Verfahren sind noch kompakter und dafür noch langsamer.
    Bzw. je nach Anwendung braucht man auch gar nix und kann die Binärdaten direkt in den String reinstopfen, inklusive Null-Bytes & Co.


  • Global Moderator |  Mod

    @hustbaer sagte in Strings als Container für Rohdaten "missbrauchen":

    Bzw. je nach Anwendung braucht man auch gar nix und kann die Binärdaten direkt in den String reinstopfen, inklusive Null-Bytes & Co.

    Was wieder ein hervorragender Grund gegen Stringtypen ist, denn bei den Stringtypen muss man erst forschen, ob sie damit zurecht kommen (und die Strings der populären Sprache C kämen beispielsweise nicht mit \0 in den Daten zurecht), wohingegen man sich bei den Rohdatentypen sicher sein kann, dass alles funktioniert.



  • @SeppJ sagte in Strings als Container für Rohdaten "missbrauchen":

    Was wieder ein hervorragender Grund gegen Stringtypen ist, denn bei den Stringtypen muss man erst forschen, ob sie damit zurecht kommen

    Ja, stimmt schon. Ich meine nur: wenn man aus irgend einem Grund Binärdaten über z.B. std::string transportieren muss, wegen irgend einer blöden vorgegebenen API, dann kann man sich das mal überlegen. Wobei dann natürlich immer noch die Gefahr lauert dass die Library die diese API definiert/verwendet davon ausgeht dass alles was in dem std::string daherkommt auch "printable" ist.

    Also ja, alles in allem ne schlechte Idee.



  • @hustbaer sagte in [Strings als Container für Rohdaten "missbrauchen"]

    Ja, stimmt schon. Ich meine nur: wenn man aus irgend einem Grund Binärdaten über z.B. std::string transportieren muss, wegen irgend einer blöden vorgegebenen API, dann kann man sich das mal überlegen.

    Ich will einem speziellen, exotischen, System den Umgang mit Audio-Daten beibringen. Dazu muss es die Möglichkeit haben, Wave-Dateien wiederzugeben. Diese sind entweder synthetische Sprachschnipsel oder Sinus-Töne verschiedener Frequenz. Die beiden einzigen Möglichkeiten, über die die Komponenten miteinander BLOBs austauschen können sind (Java)Strings und Arrays aus Double-Werten. Ich könnte auch jeweils 8 Bytes in ein Double quetschen. Wäre auch eine Möglichkeit.



  • Aber das ist doch eine andere Anforderung, als du ursprünglich geschrieben hast. Du "musst" nicht Binärdaten in einen String packen, du musst die Daten irgendwie serialisieren. Da stehen dir alle Möglichkeiten offen, könntest z.B. auch XML oder JSON nehmen (würde ich aber nicht empfehlen). Besser wär wahrscheinlich Base64 oder Base85.
    Wenn Performance sehr wichtig ist, wäre es vermutlich performanter, die Daten binär in das double array zu packen.



  • @Mechanics sagte in Strings als Container für Rohdaten "missbrauchen":

    Da stehen dir alle Möglichkeiten offen, könntest z.B. auch XML oder JSON nehmen

    Aber XML und JSON sind iherseits schon Text-basiert, können also dem Übertragungskanal nicht vorschreiben, dass er mit Rohdaten klar kommt. In XML eingebettete, fremde Datenformate sind IMHO auch meistens Base64-kodiert.



  • Ich meinte ja auch keine Rohdaten. Ich wollte damit sagen, dass du "nur" die Daten serialisieren musst und dir dabei auch alle Möglichkeiten offen stehen. Auch wenn du z.B. die Bytes einzeln ins XML schreibst
    <byte>21</byte>
    <byte>123</byte>

    Was natürlich Quatsch wäre. Aber eine halbwegs sinnvolle textuelle Serialisierung für Binärdaten zu finden ist was anderes, als die Rohdaten in einen String zu stecken.



  • @Mechanics sagte in Strings als Container für Rohdaten "missbrauchen":

    Aber eine halbwegs sinnvolle textuelle Serialisierung für Binärdaten zu finden ist was anderes, als die Rohdaten in einen String zu stecken.

    Jein, aber egal. Jetzt weißt du ja, was ich vor habe.



  • Du könntest die Daten auch als echte double-Samples übergeben. Also nicht die Binärdaten als double "interpretieren", sondern jedes Sample in einen "echten" double Wert konvertieren. Wenn man von 16 Bit Samples ausgeht dann verfierfacht sich dadurch natürlich die Datenmenge. Dafür sollte die Konvertierung aber relativ flott sein (müsstest du natürlich ausprobieren).

    Und 4x hast du z.B. auch wenn du Hex-kodierte Strings verwendest. x2 für Hex und dann nochmal x2 weil Java Strings soweit ich weiss mit den aktuellen VMs intern immer noch UTF-16 sind.

    Was Binärdaten in double packen angeht: Ich hab das noch nie selbst probiert, aber ich hätte Bedenken wegen NaNs. Einerseits gibt's viele verschiedene Representationen für NaN, und ich weiss nicht ob du davon ausgehen kannst dass die genaue NaN Representation beibehalten wird. Und dann gibt es noch die "signalling" NaNs - und dass dir beim Kopieren des Arrays ne Exception um die Ohren fliegt weil das Bit-Pattern ein signalling NaN darstellt ist vermutlich nicht wünschenswert.


    Davon abgesehen: Base64 oder auch einfach Hex scheint mir vernünftig.



  • @hustbaer sagte in Strings als Container für Rohdaten "missbrauchen":

    Davon abgesehen: Base64 oder auch einfach Hex scheint mir vernünftig.

    Mir inzwischen auch. Die Hardware ist nicht gerade leistungsstark und muss auch noch mit dem ganzen Java-Overhead klar kommen. Ich denke ich werde Base64 nehmen. ☺