Entwickler-Ecke
Basistechnologien - Problem mit Typen-Konvertierung
m.keller - Do 16.01.14 14:48
Titel: Problem mit Typen-Konvertierung
Hallo,
Ich habe folgendes Problem:
Ich nutze ein SQL-reader um Daten aus eine MSSQL DB zur verfühgung zu stellen.
Mit diesem reader lese ich die Spalten der Tabelle aus.
Nun gibt es eine Spalte den type varbinary.
Wenn ich diesen Wert einer Variable übergebe und diese ausgeben lasse bekomme ich nur als wert
System.Byte[].
Leider bekomme ich diesen nicht in ein Unicode Konvertiert.
Ich fände toll wenn mir dabei jemand helfen kann.
vielen dank
Moderiert von
Th69: Titel geändert.
Moderiert von
Th69: C#-Tags hinzugefügtModeriert von
Christian S.: Topic aus WinForms verschoben am Di 25.02.2014 um 08:56
Ralf Jansen - Do 16.01.14 15:04
Encoding hat eine GetString Methode wo du dein Byte Array reinschieben kannst um einen String zu bekommen. Du mußt nur das richtige Encoding wählen. In erster Näherung vermutlich utf8.
Dann also
C#-Quelltext
1:
| var meinLieberString = Encoding.UTF8.GetString(meinLiebesLiebesByteArray); |
m.keller - Do 16.01.14 15:09
Danke,
das habe ich schon versucht.
Da meckert mich nur VS an...
C#-Quelltext
1: 2:
| Fehler 1 Die beste Übereinstimmung für die überladene System.Text.Encoding.GetString(byte[])-Methode hat einige ungültige Argumente. Fehler 2 1-Argument: kann nicht von "object" in "byte[]" konvertiert werden. |
hier am besten noch ein ausschnitt vom Script
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| for (int i = 0; i < resultUploadKeys.Length; i++) {
print_log(Encoding.UTF8.GetString(reader[resultUploadKeys[i]])); } |
alle anderen werte werden korrekt ausgelesen.
Palladin007 - Do 16.01.14 15:25
Du bekommst von Reader ja auch kein Objekt vom Typ byte[], sondern vom Typ object und das musst du erst als byte[] casten:
C#-Quelltext
1:
| Encoding.UTF8.GetString((byte[])reader[resultUploadKeys[i]]); |
Aber warum eigentlich als string? Ich würde den Typ dazu nutzen, Daten zu speichern, die du auch als byte-Array hast, wie z.B. den Inhalt einer Datei. Da bietet sich meiner Meinung nach an, das byte-Array so in die Datenbank zu legen und auch so wieder in einen Stream ein zu lesen.
m.keller - Do 16.01.14 15:35
Danke,
casten habe ich bis jetzt noch nie was von gehört aber gut zu wissen :-)
Es ist ein etwas älteres System und nur mit varbinary ist es möglich alle Daten ein zu pflegen.
Irgendwie bekomme ich daraus jetzt nur keine Werte.
Ralf Jansen - Do 16.01.14 15:52
Zitat: |
Es ist ein etwas älteres System und nur mit varbinary ist es möglich alle Daten ein zu pflegen. |
Das ist aber auch das einzige was man mit binär Typen kann ;) Jegliches Features alles join, durchsuchen etc. wofür sich eine relationale Datenbank explizit anbietet ist damit ausgeschlossen. Man kann sie nur reinwerfen und wieder rausholen. Da du scheinbar in deinem Code über Spalten iterierst und damit alle oder fast alle Spalten varbinary sind un dnicht nur eine hört sich das doch ausgesprochen kontraproduktiv an. Insbesondere wenn das da drin nicht ursprünglich binäre Daten sind sondern einfach nur Text.
m.keller - Do 16.01.14 15:57
Es ist nur eine Ergebnisspalten von diesem Type.
Der Rest hat andere Typen.
In dieser Spalte sind nur Messwerte abgelegt.
Ich bin auch nicht glücklich damit, aber wie heist es so schön "kunde ist König".
Jetzt ist System.Byte weg, allerdings bekomme ich auch keine Werte aus der Spalte.
Palladin007 - Do 16.01.14 16:32
Naja, für Messwerte würde sich doch eigentlich eine weitere Tabelle anbieten?
Da stehen dann wichtige Daten der Messung drin und die Messwerte selber, dazu noch die Number des Auftrages. Zumindest so in der Art.
Was meinst du damit:
Zitat: |
Jetzt ist System.Byte weg |
Und wenn du keine Werte bekommst, ist der Fehler irgendwo anders. Ein schöner Fehler ist ja, dass man testweise Daten in VisualStudio über den ServerExplorer bei der Datenbank direkt einträgt und dann beim Auslesen zur Laufzeit keine zurück bekommt. Das kann passieren, wenn man beim Entwickeln mit einer Datebank arbeitet, die irgendwo liegt, die Master-Datenbank oder so, während die SOftware aber eine ganz andere Datenbank verwendet, die als Kopie der Master-Datenbank erstellt wurde.
Das ist mir zumindest mal bei Sql Server Compact passiert, da passiert das einfach, ist ja nur eine Datei ^^
m.keller - Do 16.01.14 16:42
Naja, wie am Anfang ich beschrieben hatte das ich den Variablen Typ ausgegeben bekomme.
Das wird nun nicht mehr ausgegeben.
Die werte habe ich in der MSSQL Datenbank mir generieren lassen.
Einfach fortlaufende Nummern.
Die Datenbank ist auf dem System Test weise Installiert.
Vielleicht über sehe ich gerade auch ne Kleinigkeit und sollte mal Feierabend machen.
Palladin007 - Do 16.01.14 16:50
Es reicht auch schon ein Kaffee oder eine Runde an der frischen Luft ^^
Du meinst, vor dem Cast hast du ein byte[] bekommen und nach dem Cast zum byte[] nicht mehr?
Das klingt irgendwie seltsam
Sicher, dass du einfach nur den Typ, den die Daten hinter object tatsächlich haben (also byte[]), in Klammern davor geschrieben hast?
C#-Quelltext
1: 2: 3: 4: 5:
| for (int i = 0; i < resultUploadKeys.Length; i++) { var binaryData = (byte[])reader[resultUploadKeys[i]]; print_log(Encoding.UTF8.GetString(binaryData)); } |
m.keller - Do 16.01.14 16:57
Ich habe es so:
C#-Quelltext
1: 2: 3:
| resultUploadValues[i] = (byte[]) reader[resultUploadKeys[i]]; print_log("convertiert" + " " + resultUploadKeys[i] + " " + Encoding.UTF8.GetString(resultUploadValues[i])); |
resultUploadValues[i] ist vom Typ string
Th69 - Do 16.01.14 17:27
Hallo,
also die Grundlagen von Datentypen und Datentypen-Konvertierungen ('casten') sollte man schon beherrschen, wenn man sich mit komplexeren Sachen wie Datenbanken beschäftigt.
Du hast anscheinend die Hinweise von Ralf und Palladin007 nicht wirklich verstanden. Dein letzter Code kann ja nicht funktionieren, denn du kannst nun mal nicht direkt ein Objekt vom Typ byte[] einem String zuweisen. Dafür gibt es die von Ralf angesprochene Methode und diese mußt du dann hier einsetzen (und nicht erst bei der Ausgabe eine Zeile später).
m.keller - Do 16.01.14 17:31
Das habe ich ja aber es bringt leider nicht das gewünschte Ergebniss --> Wert aus der Datenbank
ich hatte anscheinend noch die Falschen Zeilen in der Zwischenablage
Dies habe ich probiert.
C#-Quelltext
1: 2:
| resultUploadValues[i] = Encoding.UTF8.GetString((byte[])reader[resultUploadKeys[i]]); print_log("convertiert" + " " + resultUploadKeys[i] + " " + resultUploadValues[i]); |
und in der Datenbank sind ganz sicher werte vorhanden, wie z.B. 0x00000001
Palladin007 - Do 16.01.14 18:05
Du sagst, vorher sind ganz sicher die richtigen Daten vorhanden. Setze dort doch mal einen Breakpoint und schaue, ob die da sind und wann sie dann nicht meher wie gewollt vorhanden sind. Der Code, der daran schuld ist, dass sie "verschwinden" dürfte dir Aufschluss darüber geben, wo sie geblieben sind. Ich kann allein in der Konvertierung zumindest keinen Fehler erkennen.
Und wenn das Problem in der Schleife liegt, wo du dann den String vom Array haben willst, dann lege mal die einzelnen Objekte in einzelne Variablen und schau dir so dann den Inhalt an, während er Punkt für Punkt vom Objekt aus dem DataReader zum String verarbeitet wird.
Th69 - Do 16.01.14 20:14
Hallo nochmal,
du schreibst
m.keller hat folgendes geschrieben: |
und in der Datenbank sind ganz sicher werte vorhanden, wie z.B. 0x00000001 |
Dies ist aber dann ganz sicher kein (ASCII- bzw. Unicode)-String. Du mußt schon genau wissen, in welchem Format die Messwerte abgelegt sind. Evtl. als reine Binärdaten, dann kannst du sie mit der Klasse [url]BinaryReader[/url] auslesen, z.B.
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| using(MemoryStream stream = new MemoryStream(bytes)) using(BinaryReader reader = new BinaryReader(stream)) { while(stream.Position < stream.Length) { int x = reader.ReadInt32(); } } |
(alternativ als
long, float, double mit den zugehörigen Methoden auslesen).
m.keller - Mo 24.02.14 11:54
Hallo,
das Problem ist leider doch noch nicht gelöst :-(
jetzt in der Test-fase kommen die Probleme.
Leider war mir bis zu heute nicht bekannt das die Varbinary daten aus der Datenbank 32 bit groß sein.
Nun muss ich in irgend einer art und weise 32 bit Varbinary in einen utf8 String konvertieren.
Da aber die vorige ideen von euch nur auf 16 bit funktionieren habe ich nun ein große Problem.
Wie bekomme ich die Varbinary Daten mit 32 bit interpretiert?
Und wie bekomme ich float werte eben so konvertiert?
Entweder stehe ich gerade echt am schlauch oder bin zu dumm dafür.
Ralf Jansen - Mo 24.02.14 12:08
Zitat: |
Nun muss ich in irgend einer art und weise 32 bit Varbinary in einen utf8 String konvertieren. |
Varbinary hat kein Format. Wenn irgendwas was wir vorher geraten haben funktioniert hat war das Zufall.
Wie die Daten zu interpretieren sind hängt davon ab wie sie reingeschrieben worden sind.
Also was(Integer, Float, Chars in welcher Bittigkeit und welcher Byte Reihenfolge) wurde wie in das Feld geschrieben?
m.keller - Mo 24.02.14 12:14
Zitat: |
Also was(Integer, Float, Chars in welcher Bittigkeit und welcher Byte Reihenfolge) wurde wie in das Feld geschrieben? |
Ich weis in welchem Feld ein Welcher Typ steht.
Es gibt Strings und Float Werte die alle in diesem Varbinary Feld stehten.
Alle sind in 32 bit längen aus zu lesen!
Ralf Jansen - Mo 24.02.14 12:21
Wenn unterschiedliche Typen in dem Feld stehen wodurch weißt du wann welcher Typ tatsächlich gemeint ist? Den Typ kann man denn Bytes nicht ansehen. Genausowenig die korrekte Reihenfolge der Bytes.
m.keller - Mo 24.02.14 12:26
es existiert ein weiteres Feld in der Datenbank wo mir der Type übermittelt wird.
Somit kann ich davon ausgehen, dass es entweder um ein String oder floate geht.
Ralf Jansen - Mo 24.02.14 12:35
Bei string gilt weiterhin das über die Encoding Klasse zu machen. Wieviele Bytes das sind macht keinen Unterschied. Der Zieltext hat halt nur eine andere Länge.
Float über BitConverter.ToSingle
C#-Quelltext
1: 2: 3: 4:
| float result = BitConverter.ToSingle(deinLiebesByteArray, 0); string result = Encoding.UTF8.GetString(deinLiebesByteArray); |
m.keller - Mo 24.02.14 12:50
Danke.
Wenn ich den String auswerte, bekomme ich allerdings nur "\0\0\a�" raus, der Wert des varbinary Feld ist 0x000007E6.
Dass kann doch dann auch nicht stimmen.
Th69 - Mo 24.02.14 12:53
Welchen String-Wert erwartest du denn bei 0x000007E6?
m.keller - Mo 24.02.14 13:01
Laut Zulieferer sollte es 2022 sein. Angeblich 32 bit hex.
Ralf Jansen - Mo 24.02.14 13:09
Das wäre einfach der Integerwert. Also nix Float oder string.
m.keller - Mo 24.02.14 13:12
naja an sich ja.
Laut Zulieferer, hat er diesen wert in ein String konvertiert und diesen dann in ein varbinary eingetragen. Es kann dort auch ein String von einem Datum enthalten sein.
"0x000007E6" muss Komplet betrachtet werden! Wenn ich den String den ich raus bekommen habe interpretiere, wurde 00 zu 0 konvertiert und 07 zu a un E6 zu einem unbekannte Zeichen.
Ralf Jansen - Mo 24.02.14 14:23
Zitat: |
"0x000007E6" muss Komplet betrachtet werden! Wenn ich den String den ich raus bekommen habe interpretiere, wurde 00 zu 0 konvertiert und 07 zu a un E6 zu einem unbekannte Zeichen. |
Nein. utf-8 hat keine fixe Zeichenlänge. Jedes Zeichen ist zwischen 1 und 4 Byte lang und nicht 1 Byte = 1 Zeichen. Da das hier aber sicher kein string ist könnte es trotzdem zufällig so auskommen wie du denkst es bleibt aber Müll. Falls du das nicht glaubst dann bedenke auch eins gilt bei utf-8, jedes Zeichen wird immer gleich kodiert. Wenn es also 2022 als Zeichenfolge wäre sollte da 3 mal die selbe ByteFolge auftauchen was es doch wohl ganz offensichtlich nicht tut.
7E6 ist die Hex Darstellung von 2022 dezimal. Kannst du mit jedem Taschenrechner nachrechnen. Kriegt sogar der von Windows hin. Deine Bytefolge die du da hast ist die direkte Integerdarstellung von 2022.
m.keller - Mo 24.02.14 14:41
Es ist ein Int wert der aber als Text ausgegeben werden soll.
Das Problem ist das eine Zeile weiter ein Datum drin stehen kann,in der nächsten Zeile ein normaler text und in der dann darauf folgenden ein Hex-String.
Wenn ich mit dem View in der Datenbank die Werte mit cast(varbinaryWert as varchar(max)) auslese dann bekomme ich die gewünschten werte.
Dieses wäre aber fatal wenn ich ein Hex-String mit 8000 Zeichen auslesen will. Dies kann er nicht umwandeln!
Quelltext
1: 2: 3:
| 0x33382C303030 0x33392C303030 0x00009C4000009C4000009C4000009C4000009C4000009C4000009C4000009C4000009C4000009C4000009C4000009C4000009C4000009C4000009C4000009C400000 |
das sind Werte von drei Zeilen.
Quelltext
1:
| 2014/02/21_13:23:12 0x323031342F30322F32315F31333A32333A3132 |
von einer vierten mit dem Richtigen Wert
Ralf Jansen - Mo 24.02.14 15:04
Zitat: |
Es ist ein Int wert der aber als Text ausgegeben werden soll. |
Also Byte[] mit Bitconverter.ToInt32 in einen Integer wandeln und dann nach string casten.
Zitat: |
Wenn ich mit dem View in der Datenbank die Werte mit cast(varbinaryWert as varchar(max)) auslese dann bekomme ich die gewünschten werte. |
Nach dem was du uns erzählt hast bezweifle ich das. Kurzer Test
SQL-Anweisung
1: 2:
| Declare @data varbinary(max) = 0x000007E6 select cast(@data as varchar(max)) as [varchar], cast(@data as int) as [int], cast(@data as datetime) as [datetime] |
liefert
Quelltext
1: 2:
| varchar int datetime 2022 1900-01-01 00:00:06.740 |
Da da 0er Bytes stehen werden die wahrscheinlich als Textende interpretiert und als varchar bekommst du gar nix bei 0x000007E6.
m.keller - Mo 24.02.14 15:32
0x000007E6 liefert bei Varchar(max) die 2022
der andere Wert ist das Datum.
Ralf Jansen - Mo 24.02.14 15:37
Zitat: |
0x000007E6 liefert bei Varchar(max) die 2022 |
Dann ist dein Wert bereits ein Int und kein Varbinary. Wäre es tatsächlich ein Varbinary würdest du die 2022 nicht bekommen. Du sprachst eben in einem Nebensatz von einem View. Konvertiert der eventuell schon bevor du auch noch Hand anlegst?
m.keller - Mo 24.02.14 15:39
Nein nur wenn ich den view bearbeite und cast(varbinaryWert as varchar(max)) eintrage.
m.keller - Mo 24.02.14 15:44
SQL-Anweisung
1: 2: 3: 4: 5:
| SELECT [VALUE] ,cast([VALUE] as Varchar(max)) FROM [Data]
where ResultID = 22 |
Quelltext
1: 2: 3: 4: 5: 6: 7:
| 0x48616C6C6F2057656C74 Hallo Welt 0x33363230303030303030313733303431 3620000000173041 0x0000041100000412000004130000041400000415000004160000041700000418000004190000041A0000041B0000041C0000041D0000041E0000041F0000042000 0x000007D7 0x000007D8 0x000007D9 0x000007DA |
Mit dem SQL befehl bekomme ich die daten angezeigt.
Die ersten beiden Werte habe ich für Testzwecke geändert.
Die unteren werden gar nicht erst ausgegeben.
m.keller - Mo 24.02.14 17:07
wir weichen aber gerade von der eigentlichen Frage ab.
Ich bekomme aus der Datenbank das varbinary Feld leider nur mit einem Reader als byte[] ausgelesen.
Wie kann ich dieses direkt in einen string schreiben?
Und für die anderen Werte, wie kann ich diese umwandeln, in ein String?
Ralf Jansen - Mo 24.02.14 17:16
Zitat: |
Ich bekomme aus der Datenbank das varbinary Feld leider nur mit einem Reader als byte[] ausgelesen |
Nicht leider sondern zwangsweise. Alles ist binär nur in dem man sagt "interpretiere mir das als Integer, Float, String mit den entsprechenden Regeln" kommt am Ende was sinnvolles raus (bei der Wahl der richtigen Regeln). Dafür gibt es ja unterschiedliche Datentypen in der Datenbank (und in Programmiersprachen etc.) damit man weiß wie die Bitfolgen zu interpretieren sind und das Automatisch richtig interpretiert werden kann. Wenn du das in der Datenbank typfrei (als irgendein Binärtyp) ablegst bist du der Einzige der sagen kann wie das zu interpretieren ist und mußt dann auch die entsprechenden Regeln einhalten.
Zitat: |
Und für die anderen Werte, wie kann ich diese umwandeln, in ein String? |
Da drehen wir uns jetzt im Kreis. Du mußt erst wissen was es ist. Dann mußt du das in diesen Typ ändern und dann in einen String (wenn es nicht eh schon ein string passender Encodierung war).
Also wenn du weißt das es ein Integer ist (wie bei dem 7E6 zu 2022 Ding) mußt du die Bytes in Integer ändern und dann den Integer in einen String.
m.keller - Di 25.02.14 12:23
Ich versuche es jetzt mit einer Sache bzw Frage.
Ich muss einen Binär String auslesen diese beträgt im normal Fall 4069 Byte.
wenn ich wie ihr das vorgeschlagen habt
C#-Quelltext
1:
| byte[] binaryData = (byte[])reader["array"] |
bekomme ich die gleichen werte wie als wenn ich den Reader mir angucke.
D.h. ich bekomme lauter zahlen werte, keine Hex.
Ich muss diesen langen Binär string aber als Hex in einem String übergeben.
Wenn das erst ein mal Funktioniert, dann bin ich ein großen Schritt weiter
Th69 - Di 25.02.14 12:42
Hallo,
um diesen Thread mal zum Abschluß zu bringen, solltest du mal etwas konkreter werden.
Was genau möchtest du als Stringausgabe haben - gib mal ein Beispiel (ich glaube immer noch, daß dir die Grundlagen von Datentypen nicht klar sind, wenn ich so deine Formulierungen bzgl. "D.h. ich bekomme lauter zahlen werte, keine Hex." lese...).
m.keller - Di 25.02.14 12:49
Also noch mal kurz, ich lese z.B. ein varbinary Feld mit dem Wert den mir MSSQL anzeigt "0x00009ccA".
Wenn ich mir die Daten in c# im Debug angucke, bekomme ich 4 byte mit den werten {0;0;156;202}
Mit
C#-Quelltext
1:
| string.Format("{0:X}", readerNew.ReadByte() |
Bekomme ich leider nur "009ccA"raus eigentlich müsste er daraus ein Ergebnis machen wie oben.
Warum kann er die ersten 00 nicht in ascii interpretieren?
Christian S. - Di 25.02.14 13:45
ReadByte liefert nur ein einzelnes Byte zurück, da passt also schon irgendwas nicht ...
m.keller - Di 25.02.14 13:47
wird in einer schleife aufgerufen biss alle Bytes gelesen worden sind.
Christian S. - Di 25.02.14 13:52
Zeig mal einen kompletten Quelltext, der in sich schlüssig ist und der das Problem zeigt.
m.keller - Di 25.02.14 13:58
habe den Fehler gefunden.
C#-Quelltext
1: 2: 3: 4:
| while (readerNew.BaseStream.Position < readerNew.BaseStream.Length) { resultUploadValues[(j * resultUploadKeys.Length) + i] = resultUploadValues[(j * resultUploadKeys.Length) + i] + string.Format("{0:X2}", readerNew.ReadByte()); } |
Der Fehler war {0:X} --> {0:X2}
Moderiert von
Christian S.: Beiträge zusammengefasstdamit bekomme ich zu mindestens die Hex werte alle raus.
Den Rest habe ich jetzt in dem view mit cast(Feld as Varchar(max)) geändert
Ist zwar nicht schön und stellt mich gerade nicht zufrieden, aber es funktioniert erst ein mal.
Ralf Jansen - Di 25.02.14 16:12
Zitat: |
Warum kann er die ersten 00 nicht in ascii interpretieren? |
Weil der Wert 0 in Ascii Ende des strings bedeutet. 0 wie auch einige andere Werte sind keine druckbaren Zeichen.
http://de.wikipedia.org/wiki/Nullzeichen
Th69 - Di 25.02.14 16:37
Hallo Ralf (und auch m.keller),
nein, der Fehler war ein anderer:
da in der Schleife
s = s + string.Format("{0:X}", readerNew.ReadByte() ausgeführt wurde, sind für die 4 Werte {0;0;156;202} die 4 Teilstrings "0", "0", "9c" "ca" erzeugt worden, so daß als Gesamtstring dann "009cca" herauskam (eben weil bei den einstelligen Hexstrings die vordere "0" nicht ausgegeben wurde - und dies wurde eben durch die Formatangabe "{0:X2}" korrigiert).
Auch wenn der Titel dieses Beitrags "Problem mit Typen-Konvertierung" lautet, so hatte es die ganze Zeit nichts mit dem Konvertieren des Byte-Arrays aus der Datenbank zu tun. Hätte
m.keller von anfang gleich die richtige Problemstellung gepostet, wäre es gar nicht zu diesen (beiderseitigen) Fehlinterpretationen gekommen.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!