Ausgabe short nach File

Ich möchte einen short-Wert im Little Endian-Format auf ein File ausgeben. Ich habe zwar ein Verfahren gefunden aber ich finde es ziemlich haarsträubend; sprich es gefällt mir nicht.


protected void methode() {
    ...
    short wert=80;
    byte[] bytes=shortToByteArray(wert);
    StringBuffer littleEndian = new StringBuffer();
    littleEndian.append(bytes[1]);
    littleEndian.append(bytes[0]);
  
    bufferedWriter.write(littleEndian.toString());
}

protected byte[] shortToByteArray(short a) {
	byte[] ret = new byte[2];
	ret[1] = (byte) (a & 0xFF);   
	ret[0] = (byte) ((a >> 8) & 0xFF);   
	return ret;
}

Das habe ich jetzt direkt in den Editor eingegeben; es kann also durchaus ein Tippfehler drin sein. Aber die Idee sollte deutlich werden.
Ich denke es sollte einen deutlich eleganteren Ansatz geben.

mfg
Ulrich

Wie wäre es mit:

    return (short)(s << 8 | s >> 8);
}```

Java ist nun mal Big Endian, was genau gefällt dir denn nicht?

Der StringBuffer ist natürlich käse, das muss schiefgehen: was soll das?

Buffer sind die besseren Arrays.

ShortBuffer shortBuffer = ByteBuffer.wrap(toWrite).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
// write shorts to shortBuffer
// write toWrite into Stream```

[QUOTE=Bleiglanz]Java ist nun mal Big Endian, was genau gefällt dir denn nicht?

Der StringBuffer ist natürlich käse, das muss schiefgehen: was soll das?[/QUOTE]

Wieso soll das schiefgehen - das Ganze funktioniert wunderbar. Sieht nur nicht schön aus. Und die Darstellung der Daten wird durch die Anwendung unter der sie benötigt werden bestimmt und nicht durch die Programmiersprache.

Man nimmt einfach keine Reader/Writer für rohe Bytes. It is not done.

[QUOTE=Spacerat]Buffer sind die besseren Arrays.

ShortBuffer shortBuffer = ByteBuffer.wrap(toWrite).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
// write shorts to shortBuffer
// write toWrite into Stream```[/QUOTE]

Danke für den Hinweis. Damit und mit der Javadoc bin ich jetzt zu dieser Löcung gekommen.

ByteBuffer bb = ByteBuffer.allocateDirect(2);
ShortBuffer shortBuffer=bb.putShort(0, a).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();



Wünschen würde ich mir einen OutputDatastream der das automatisch macht; schließlich ist LittleEndian durch Intel vermutlich mehr verbreitet als BigEndian. 
Von Google gibt es das (com.google.common.io.LittleEndianDataOutputStream), wie ich jetzt gefunden habe. Aber ohne größere Not will ich die Klasse lieber nicht für den Classpath des Programms voraussetzen.

Jedenfalls danke nochmal; hat mir sehr geholfen.

Eigentlich hatte ich um konstruktive Vorschläge gebeten. Einfach nur Besserwisserei kannst Du gerne bei Dir behalten.

Bau dir doch einen… Ich hab’ das schon mal für 'nen InputStream gemacht, vllt. kannst den ja ummodeln.

import java.nio.*;

public class OrderedDataInputStream extends InputStream {
	protected final InputStream parent;
	private ByteOrder order;

	public OrderedDataInputStream(InputStream parent) {
		this(parent, null);
	}

	public OrderedDataInputStream(final InputStream parent, ByteOrder order) {
		if (parent == null) {
			throw new NullPointerException();
		}
		this.parent = parent;
		setOrder(order);
	}

	public final void setOrder(ByteOrder order) {
		if (order == null) {
			order = ByteOrder.nativeOrder();
		}
		this.order = order;
	}

	public final ByteOrder getOrder() {
		return order;
	}

	@Override
	public int read() throws IOException {
		return parent.read();
	}

	public int read(ByteBuffer buffer) throws IOException {
		if (buffer.remaining() == 0) {
			return 0;
		}
		byte[] b = new byte[buffer.remaining()];
		int rc = read(b, 0, b.length);
		buffer.put(b, 0, rc);
		return rc;
	}

	public final byte readByte() throws IOException {
		return (byte) readBytes(1);
	}

	public final short readUnsignedByte() throws IOException {
		return (short) readBytes(1);
	}

	public final short readShort() throws IOException {
		return (short) readBytes(2);
	}

	public final int readUnsignedShort() throws IOException {
		return (int) readBytes(2);
	}

	public final char readChar() throws IOException {
		return (char) readBytes(2);
	}

	public final int readInt() throws IOException {
		return (int) readBytes(4);
	}

	public final int read24Bit() throws IOException {
		return (int) readBytes(3);
	}

	public final long read48Bit() throws IOException {
		return readBytes(6);
	}

	public final long readLong() throws IOException {
		return readBytes(8);
	}

	public final long readUnsingnedInt() throws IOException {
		return readBytes(4);
	}

	public final float readFloat() throws IOException {
		return Float.intBitsToFloat((int) readBytes(4));
	}

	public final double readDouble() throws IOException {
		return Double.longBitsToDouble(readBytes(8));
	}

	public final String readUTF() throws IOException {
		int utflen = readUnsignedShort();
		byte[] bytearr = null;
		char[] chararr = null;
		bytearr = new byte[utflen];
		chararr = new char[utflen];

		int c, char2, char3;
		int count = 0;
		int chararr_count = 0;

		if (read(bytearr, 0, utflen) != utflen) {
			throw new IOException("end of file");
		}

		while (count < utflen) {
			c = bytearr[count] & 0xff;
			if (c > 127) {
				break;
			}
			count++;
			chararr[chararr_count++] = (char) c;
		}

		while (count < utflen) {
			c = bytearr[count] & 0xff;
			switch (c >> 4) {
				case 0:
				case 1:
				case 2:
				case 3:
				case 4:
				case 5:
				case 6:
				case 7:
	            /* 0xxxxxxx */
					count++;
					chararr[chararr_count++] = (char) c;
					break;
				case 12:
				case 13:
                /* 110x xxxx 10xx xxxx */
					count += 2;
					if (count > utflen) {
						throw new UTFDataFormatException(
								"malformed input: partial character at end");
					}
					char2 = bytearr[count - 1];
					if ((char2 & 0xC0) != 0x80) {
						throw new UTFDataFormatException(
								"malformed input around byte " + count);
					}
					chararr[chararr_count++] = (char) (((c & 0x1F) << 6) | (char2 & 0x3F));
					break;
				case 14:
				/* 1110 xxxx 10xx xxxx 10xx xxxx */
					count += 3;
					if (count > utflen) {
						throw new UTFDataFormatException(
								"malformed input: partial character at end");
					}
					char2 = bytearr[count - 2];
					char3 = bytearr[count - 1];
					if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) {
						throw new UTFDataFormatException(
								"malformed input around byte " + (count - 1));
					}
					chararr[chararr_count++] = (char) (((c & 0x0F) << 12)
							| ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
					break;
				default:
				/* 10xx xxxx, 1111 xxxx */
					throw new UTFDataFormatException("malformed input around byte "
							+ count);
			}
		}
		return new String(chararr, 0, chararr_count);
	}

	private long readBytes(int count) throws IOException {
		byte[] b = new byte[count];
		read(b, 0, count);
		long rc = 0L;
		if (order == ByteOrder.LITTLE_ENDIAN) {
			for (int n = 0; n < count; n++) {
				rc <<= 8;
				rc |= (b[n] & 0xFF);
			}
		} else {
			for (int n = count - 1; n >= 0; n--) {
				rc <<= 8;
				rc |= (b[n] & 0xFF);
			}
		}
		return rc;
	}
}```

das hat nichts mit besserwisserei zu tun , sondern einfach damit das man nun mal einfach keine „zeichen“ für rohe byte-werte nimmt

und das trifft auf Reader/Writer genau so zu wie eben auf einen String bzw dessen Buffer/Builder , weil dort intern mit einem char-array gearbeitet wird

und „-96“ sehen in einem char nun mal anders aus als in einem byte , womit du durch das casten die werte komplett durcheinander bringst

zusätzlich kann es zu problemen mit verschiedenen charsets kommen , weil java nun mal UTF-8 ist , viele daten unter windows aber gerne mal als ANSI oder WIN-1251 gespeichert werden , was dann zu wunderschönen fehlern führt bei denen man für die ursachenforschung mehr zeit braucht als es ein mal richtig zu lernen

[QUOTE=Unregistriert]das hat nichts mit besserwisserei zu tun , sondern einfach damit das man nun mal einfach keine “zeichen” für rohe byte-werte nimmt

und das trifft auf Reader/Writer genau so zu wie eben auf einen String bzw dessen Buffer/Builder , weil dort intern mit einem char-array gearbeitet wird

und “-96” sehen in einem char nun mal anders aus als in einem byte , womit du durch das casten die werte komplett durcheinander bringst

zusätzlich kann es zu problemen mit verschiedenen charsets kommen , weil java nun mal UTF-8 ist , viele daten unter windows aber gerne mal als ANSI oder WIN-1251 gespeichert werden , was dann zu wunderschönen fehlern führt bei denen man für die ursachenforschung mehr zeit braucht als es ein mal richtig zu lernen[/QUOTE]

Mein Einwurf war nicht so gemeint, dass ich die Bemerkung für falsch halte sondern für wenig hilfreich. Ich hatte eine relativ konkrete Frage nach Hilfestellung gestellt und als Antwort kommt ziemlich unspezifisch wie blöd die Angelegenheit doch sei.
Ich denke die Fragestellung ist auch nicht deutlich geworden. Ich wollte keine Zeichen darstellen sondern nur die Bytes im short umsortieren. Und dazu brauchte ich Zugriff auf diese Bytes.
Ob man die Zeichen jetzt mit ‘write(byte[])’ ausgibt oder sie über das casten nach char in einem String anordnet und dann mit ‘write(String)’ wegschreibt war für die Frage nicht so wichtig; ich hatte es nur aufgeführt um zu zeigen was ich vorhatte.
Codepages dienen der Abbildung der Bytes auf ein bestimmtes Zeichen. Aber das hat mich, wie gesagt, im vorliegenden Fall gar nicht interessiert. Ich wollte nur von BigEndian nach LittleEndian umschlüsseln.

Meine Lösung insgesamt sieht jetzt so aus:



{
   ...
   DataOutputStream outStream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(outputFile)));
   short recordLength = getLittleEndian((short)record.length());
   outStream.writeShort(recordLength);
   outStream.writeChars(record);
   ...
}
public static short getLittleEndian(short value) {
   ByteBuffer bb = ByteBuffer.allocateDirect(2);
   ShortBuffer shortBuffer=bb.putShort(0, value).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
   return shortBuffer.get();
}

Das Satzlängenfeld eines Satzes der Länge 80 (0x0050) wird damit als 0x5000 ins file geschrieben. Das hat auch vorher gut funktioniert; nur ist es jetzt über installierte Methoden erreicht worden.

[ot]Kann es sein, dass du LITTLE_ENDIAN mit BIG_ENDIAN verwechselst? Das ist keine Schande, zumindest nicht, solange es mir auch passiert(e) :wink:
0x0050 ist in LITTLE_ENDIAN „00 50“ (niederwertigste Byte steht hinten) und in BIG_ENDIAN „50 00“ (höchstwertigstes Byte steht hinten).[/ot]
Ansonsten… wie weit bist du mit dem umschreiben meines InputStreams? (Mach hinne, ich brauch’ den auch… :lol:)

[QUOTE=Spacerat]Bau dir doch einen… Ich hab’ das schon mal für 'nen InputStream gemacht, vllt. kannst den ja ummodeln.

[/QUOTE]
Herzliche Dank, kann ich gut gebrauchen werde ich für mich adaptieren.

[QUOTE=Spacerat][ot]Kann es sein, dass du LITTLE_ENDIAN mit BIG_ENDIAN verwechselst? Das ist keine Schande, zumindest nicht, solange es mir auch passiert(e) :wink:
0x0050 ist in LITTLE_ENDIAN „00 50“ (niederwertigste Byte steht hinten) und in BIG_ENDIAN „50 00“ (höchstwertigstes Byte steht hinten).[/ot]
Ansonsten… wie weit bist du mit dem umschreiben meines InputStreams? (Mach hinne, ich brauch’ den auch… :lol:)[/QUOTE]

Also ich bin ganz sicher hier nichts verwechselt zu haben. BigEndian entspricht unserer hexadezimalen Lesart; die Wertigkeit der Zahlen nimmt von links nach rechts ab und bei LittleEndian wird es byteweise genau andersherum geschrieben. vgl: Wikipedia

Außerdem funktioniert die Anwendung wie erwartet.

[QUOTE=JunkerJoerg]Also ich bin ganz sicher hier nichts verwechselt zu haben. BigEndian entspricht unserer hexadezimalen Lesart; die Wertigkeit der Zahlen nimmt von links nach rechts ab und bei LittleEndian wird es byteweise genau andersherum geschrieben. vgl: Wikipedia[/QUOTE]Ich sag’ doch, das ist keine Schande. :o