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
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.
Nimm mal dies als Anhaltspunkt
Musst Du sicher noch ändern...
Aber die selbe GrundIdee dahinter.
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
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...
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 😃
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?
Das könnte an der Endianness liegen. Verschiedene Prozessortypen (Intel und Motorola) legen die Bytes in unterschiedlicher Reihenfolge ab. Siehe hierzu:
Hoffe das hilft dir.
Gruß
Dario
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...
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?
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.
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 😃
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.
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.
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]);
Was für nen Typ ist meinChar? Welches Encoding verwendest du beim StreamWriter?
Baka wa shinanakya naoranai.
Mein XING Profil.
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"
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.
@talla: hmpf... Danke für den Hinweis. =)
@Programmierhans: Vergiss es... 😉
Viele Grüße,
Markus 🙂
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?
Wie oft willst Du den Beitrag von Talla noch überlesen?
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 😦
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.
Mit dem binaryWriter klappt es, aber meine Ausgabedatei enthält auch ASCII Zeichen, also kann ich den wohl nicht benutzen.
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.
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.
@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...
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?
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 😉
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'
Hinter das ToCharArray noch Klammern.
Hallo shangzung,
und beachte bitte [Hinweis] Wie poste ich richtig? Punkt 1.1.1 und [Hinweis] Syntaxfehler selbst lösen (Compilerfehlermeldungen).
herbivore