Laden...

Float als "vier unsigdner char" speichern

Erstellt von shangzung vor 14 Jahren Letzter Beitrag vor 14 Jahren 7.402 Views
S
shangzung Themenstarter:in
14 Beiträge seit 2009
vor 14 Jahren
Float als "vier unsigdner char" speichern

Hallo,

nach stundenlangem Suchen möchte ich mich an dieses Forum wenden:

Ich muss (um VTK-Dateien zu erzeugen) in C# float-Daten in eine Ausgabedatei erstellen. Jeder Wert muss hierbei durch vier unsigned char repräsentiert werden. Weiß jemand, wie ich einen float in vier unsigned char umwandle?

Vielen Dank im Voraus!
Gruß
Dmitri

6.862 Beiträge seit 2003
vor 14 Jahren

Hallo,

du brauchst die BitConverter Klasse mit der GetBytes Methode.

Aufpassen musst du nur mit den Datentypen. Wenn du sagst du willst 4 unsigned chars haben, heißt das jedes Zeichen ist nur 1 Byte groß und das ist in .Net nicht ein char sondern ein byte. Chars sind in .Net 2 Byte groß.

Baka wa shinanakya naoranai.

Mein XING Profil.

4.221 Beiträge seit 2005
vor 14 Jahren

Nimm mal dies als Anhaltspunkt

[FAQ] Von Binär nach float

Musst Du sicher noch ändern...

Aber die selbe GrundIdee dahinter.

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

4.221 Beiträge seit 2005
vor 14 Jahren

Nachtrag:

Probier es mal so:


 private static char[] FloatToCharArray(float value)
        {
            IntPtr ptr = Marshal.AllocHGlobal(4);
            Marshal.StructureToPtr(value, ptr, true);
            char[] chars=new char[4];
            chars[0]=(char)Marshal.ReadByte(ptr, 0);
            chars[1] = (char)Marshal.ReadByte(ptr, 1);
            chars[2] = (char)Marshal.ReadByte(ptr, 2);
            chars[3] = (char)Marshal.ReadByte(ptr, 3);
            Marshal.FreeHGlobal(ptr);
            return chars;
        } 

Edit: Nachtrag

Rückwärts gehts natürlich auch...


 private static float CharArrayToFloat(char[] pChars)
        {
            IntPtr ptr = Marshal.AllocHGlobal(4);
            Marshal.WriteByte(ptr, 0,(byte)pChars[0]);
            Marshal.WriteByte(ptr, 1, (byte)pChars[1]);
            Marshal.WriteByte(ptr, 2, (byte)pChars[2]);
            Marshal.WriteByte(ptr, 3, (byte)pChars[3]);
            float f = (float)Marshal.PtrToStructure(ptr, typeof(float));
            Marshal.FreeHGlobal(ptr);
            return f;
        }

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

360 Beiträge seit 2005
vor 14 Jahren

Sollte das nicht auch folgendermaßen gehen?

float myFloat = 2.76F; // Irgendein float-Wert halt...
byte[] floatBytes = BitConverter.GetBytes(myFloat);

Dann noch die bytes in chars casten und fertig? Oder bin ich da schief gewickelt?

Viele Grüße,
Markus 😃

S
shangzung Themenstarter:in
14 Beiträge seit 2009
vor 14 Jahren

Die Lösungen klappen beide, jedoch bekomme ich falsche Werte.

"1" sollte z.B: "? € nul nul" sein, ist jedoch "nul nul  €"

Woran kann das liegen?

C
401 Beiträge seit 2007
vor 14 Jahren

Das könnte an der Endianness liegen. Verschiedene Prozessortypen (Intel und Motorola) legen die Bytes in unterschiedlicher Reihenfolge ab. Siehe hierzu:

Wikipedia (Endianness)

Hoffe das hilft dir.

Gruß

Dario

4.221 Beiträge seit 2005
vor 14 Jahren

Das könnte an der Endianness liegen. Verschiedene Prozessortypen (Intel und Motorola) legen die Bytes in unterschiedlicher Reihenfolge ab. Siehe hierzu:

Denke ich auch 😃

Also dreht man das Pferd um 😃


  private static char[] FloatToCharArray(float value)
        {
            IntPtr ptr = Marshal.AllocHGlobal(4);
            Marshal.StructureToPtr(value, ptr, true);
            char[] chars=new char[4];
            chars[3]=(char)Marshal.ReadByte(ptr, 0);
            chars[2] = (char)Marshal.ReadByte(ptr, 1);
            chars[1] = (char)Marshal.ReadByte(ptr, 2);
            chars[0] = (char)Marshal.ReadByte(ptr, 3);
            Marshal.FreeHGlobal(ptr);
            return chars;
        }
        private static float CharArrayToFloat(char[] pChars)
        {
            IntPtr ptr = Marshal.AllocHGlobal(4);
            Marshal.WriteByte(ptr, 0,(byte)pChars[3]);
            Marshal.WriteByte(ptr, 1, (byte)pChars[2]);
            Marshal.WriteByte(ptr, 2, (byte)pChars[1]);
            Marshal.WriteByte(ptr, 3, (byte)pChars[0]);
            float f = (float)Marshal.PtrToStructure(ptr, typeof(float));
            Marshal.FreeHGlobal(ptr);
            return f;
        }

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

S
shangzung Themenstarter:in
14 Beiträge seit 2009
vor 14 Jahren

Stimmt, klappt gut @ Programmierhans
Aber eine Sache ist noch faul. Wenn einer der Chars den ASCII Wert "128" Beherrbergt, der übrigens von Intellisense auch nicht angezeigt wird, schreibt er anstatt "€" ein "€". Damit ist ein Char zu zwei geworden und das macht mir die Struktur kaputt. Was mache ich da falsch?

C
401 Beiträge seit 2007
vor 14 Jahren

Könnte daran liegen, dass 128 bis 159 in Unicode Steuerzeichen und somit nicht druckbar sind. Mit falschem Encoding könnte es dann sein, dass er komische Zeichen druckt.

360 Beiträge seit 2005
vor 14 Jahren

So wie ich das bis jetzt verstanden habe klappen sowohl meine Methode als auch die von Programmierhans. @Programmierhans: Rein aus Interesse: Warum hast du gerade diesen Ansatz gewählt?

Viele Grüße,
Markus 😃

S
shangzung Themenstarter:in
14 Beiträge seit 2009
vor 14 Jahren

Das Euro Zeichen ist das Zeichen 128 in den Windows Sonderzeichen. Wenn ich jedoch ein €, den char 128 oder die €-Sequenz "\u0080" tippe, erscheint das Symbol in der Binärdatei als "À". In der Beispieldatei, die mir vorliegt sind die Eurozeichen jedoch ganz normal vorhanden.

6.862 Beiträge seit 2003
vor 14 Jahren

So wie ich das bis jetzt verstanden habe klappen sowohl meine Methode als auch die von Programmierhans.

*hüstel* Guck dir mal die erste Antwort hier im Thread an 😃

@shangzung
Du darfst dich doch nicht darauf versteifen was für Zeichen in der Binärdatei sind wenn du sie mit nem Texteditor anguckst. Es kommt auf die Bytes drauf an, wie die dargestellt werden ist Sache des Texteditors - welche Encodings er verwendet. Guck dir die Datei mit nem Hexeditor an und du siehst sofort welche Bytes du geschrieben hast.

Wie schreibst du denn deine 4 Zeichen in die Datei? Hast du draufgeachtet nicht unicode zu schreiben, so wie es standard ist?

Baka wa shinanakya naoranai.

Mein XING Profil.

S
shangzung Themenstarter:in
14 Beiträge seit 2009
vor 14 Jahren

Ich benutze für Beispielfile und für meine file das Notepad++. Mit nem Hex Editor ist im Beispiel nur das Euro Zeichen (80) und in meiner Version (c2 80).

Ich schreibe die Werte so rein:
Für jeden Wert:
StreamWriter.Write(meinChar[0]);
StreamWriter.Write(meinChar[1]);
StreamWriter.Write(meinChar[2]);
StreamWriter.Write(meinChar[3]);

6.862 Beiträge seit 2003
vor 14 Jahren

Was für nen Typ ist meinChar? Welches Encoding verwendest du beim StreamWriter?

Baka wa shinanakya naoranai.

Mein XING Profil.

S
shangzung Themenstarter:in
14 Beiträge seit 2009
vor 14 Jahren

Der Typ ist char[4].

Ich habe kein Encoding angegeben!
Versuche gerade:

StreamWriter VTKFile = new StreamWriter(path, System.Text.Encoding.ASCII)
aber der Compiler meckert mit "error CS1502: The best overloaded method match for 'System.IO.StreamWriter.StreamWriter(string, bool)' has some invalid arguments"

6.862 Beiträge seit 2003
vor 14 Jahren

Hallo,

meinen Hinweis zu den Datentypen in der ersten Antwort hast du nicht zur Kenntniss genommen oder?

Wenn du 4 Char Werte schreibst, schreibst du 8 Byte in die Datei, und das ist dann kein float, sondern ein double.

Zur Fehlermeldung: Guck in die Doku, einen Konstruktor mit den Parametern wie du ihn aufrufen willst, gibt es nicht.

Leichter wärs übrigens gleich nen BinaryWriter zu benutzen statt nen StreamWriter, wenns um einzelne Bytes geht.

Baka wa shinanakya naoranai.

Mein XING Profil.

360 Beiträge seit 2005
vor 14 Jahren

@talla: hmpf... Danke für den Hinweis. =)
@Programmierhans: Vergiss es... 😉

Viele Grüße,
Markus 🙂

S
shangzung Themenstarter:in
14 Beiträge seit 2009
vor 14 Jahren

Mein einziges Problem jetz ist, dass jedes Mal, wenn einer der vier bytes einen Wert größer 127 hat, in der File nicht nur das dazugehörige Zeichen geschrieben wird, sondern zusätzlich davor das Zeichen "Â" (hex: C2)

Woran kann das liegen?

F
10.010 Beiträge seit 2004
vor 14 Jahren

Wie oft willst Du den Beitrag von Talla noch überlesen?

S
shangzung Themenstarter:in
14 Beiträge seit 2009
vor 14 Jahren

Ich soll also bytes wegschreiben? Da der Datentyp byte eine Zahl darstellt, schreibt er mir die bytes als Zahlen im ASCII format in die Ausgabedatei. Wenn ich den byte zum char caste, schreibt er mir den char wieder falsch hinein 😦

C
401 Beiträge seit 2007
vor 14 Jahren

BinaryWriter.Write(byte[])... damit klappt das wunderbar, wurde aber auch schon hier geschrieben. Das sind auch alles Grundlagen, die man einfach bei Google finden kann.

S
shangzung Themenstarter:in
14 Beiträge seit 2009
vor 14 Jahren

Mit dem binaryWriter klappt es, aber meine Ausgabedatei enthält auch ASCII Zeichen, also kann ich den wohl nicht benutzen.

F
10.010 Beiträge seit 2004
vor 14 Jahren

Vergiss bitte, was Du in anderen Programmiersprachen zu char gelernt hast.

Ein Char in .NET ist nicht das selbe wie ein byte, sondern eher wie ein int16.
Wenn du also einen Float in seiner binären representation von 32Bit sehen willst nimm
byte[4] und hör auf diese als Char[] einlesen zu wollen, das geht schief.

C
401 Beiträge seit 2007
vor 14 Jahren

Du kannst auch bei einem BinaryWriter ein Encoding angeben: BinaryWriter Constructor (Stream, Encoding)

Aber eigentlich solltest du es auch selber schaffen mal einen Blick ins MSDN zu werfen.

4.221 Beiträge seit 2005
vor 14 Jahren

@Programmierhans: Rein aus Interesse: Warum hast du gerade diesen Ansatz gewählt?

Weil es in allen .Net-Versionen funktioniert... und man die Byte-Reihefolge drehen kann und ich auch gerne sehe was abgeht... (ich code lieber selber als vor einer Blackbox zu sitzen)..

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

S
shangzung Themenstarter:in
14 Beiträge seit 2009
vor 14 Jahren

Mit dem BinaryWriter klappt es, danke!
Aber wenn ich z.B. am Anfang der Datei:

writeBinary.Write("# vtk DataFile Version 2.0\n");

mache, dann schreibt er nicht nur den String, sondern davor ein anderes Zeichen. Ist das normal beim BinaryWriter?

C
401 Beiträge seit 2007
vor 14 Jahren

BinaryWriter.Write(string) schreibt einen length prefixed string. Das heisst, dass vor dem String die Länge geschrieben wird. Rufe es einfach mit BinaryWriter.Write(string.ToCharArray()) auf, dann sollte es klappen.

edit: Klammern vergessen 😉

S
shangzung Themenstarter:in
14 Beiträge seit 2009
vor 14 Jahren

UPPS, Klammern vergessen... Sorry

Da ist was faul:

string s001 = "# vtk DataFile Version 2.0\n";
            writeBinary.Write(s001.ToCharArray);

funktioniert nicht:

error CS1502: The best overloaded method match for 'System.IO.BinaryWriter.Write(bool)' has some invalid arguments

error CS1503: Argument '1': cannot convert from 'method group' to 'bool'

C
401 Beiträge seit 2007
vor 14 Jahren

Hinter das ToCharArray noch Klammern.

S
shangzung Themenstarter:in
14 Beiträge seit 2009
vor 14 Jahren

Mein Fehler 😦

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo shangzung,

und beachte bitte [Hinweis] Wie poste ich richtig? Punkt 1.1.1 und [Hinweis] Syntaxfehler selbst lösen (Compilerfehlermeldungen).

herbivore