-- 作者:admin
-- 发布时间:4/11/2007 12:28:00 AM
-- [转帖] java的little-endian和big-endian
转自:http://blogger.org.cn/blog/more.asp?name=hongrui&id=23869 java的little-endian和big-endian 邢红瑞 发表于 2007-4-10 19:25:43 java是与CPU无关的编程语言,但是java究竟是little-endian还是big-endian呢,因为java诞生于soalris平台,最初的solaris运行于SPARC cpu上,SUN的SPARC和IBM的POWER PC均是big-endian,所以java也是big-endian。 判断java是big endian的代码 public final static int swabInt(int v) { return (v >>> 24) | (v << 24) | ((v << 8) & 0x00FF0000) | ((v >> 8) & 0x0000FF00); } public static void main(String argv[]) { // before 0x01020304 // after 0x04030201 int v = 0x01020304; System.out.println("before : 0x" + Integer.toString(v,16)); System.out.println("after : 0x" + Integer.toString(swabInt(v),16)); } // take 16-bit short apart into two 8-bit bytes. short x = 0xabcd; byte high = (byte)(x >>> 8); byte low = (byte)x;/* cast implies & 0xff */ System.out.println( "x=" + x + " high=" + high + " low=" + low ); big endian是指低地址存放最高有效字节(MSB),而little endian则是低地址存放最低有效字节(LSB)。 Big Endian 低地址 高地址 -----------------------------------------> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 12 | 34 | 56 | 78 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Little Endian 低地址 高地址 -----------------------------------------> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 78 | 56 | 34 | 12 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 如果你做单机程序,这个基本不用考虑,如何和java程序通讯也没有问题,java中在AIX下生成的对象被序列化后能够在windows下正确的反序列化,如果不这样,EJB也就不存在了。 如果你和C++的程序通讯,问题就有了,C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的,而JAVA编写的程序则唯一采用big endian方式来存储数据。 你在x86平台上,使用c语言通过socket把0x12345678发给java的serversocket,得到的是0x78563412,C程序传给JAVA程序之前有必要进行字节序的转换工作。 所有网络协议也都是采用big endian的方式来传输数据的。所以有时我们也会把big endian方式称之为网络字节序。当两台采用不同字节序的主机通信时,在发送数据之前都必须经过字节序的转换成为网络字节序后再进行传输。 c/c++中发送方htonl,接收方ntohl。 fseek(f,0L,SEEK_END); unsigned int tcount=total; tcount=htonl(tcount); memcpy( &buffer[1], &tcount, 4); Java中不用做转换。 DataOutputStream.writeInt(); DataInputStream.readInt(); c语言转换的4个宏 ntoh:network->host hton:host->network ntohs和htons针对2字节的数 ntohl和htonl针对4字节的数 为了保证代码的移植性,必须用这两个函数。 htons(): reorder the bytes of a 16-bit unsigned value from processor order to network order. The macro name can be read "host to network short." htonl(): reorder the bytes of a 32-bit unsigned value from processor order to network order. The macro name can be read "host to network long." ntohs(): reorder the bytes of a 16-bit unsigned value from network order to processor order. The macro name can be read "network to host short." ntohl(): reorder the bytes of a 32-bit unsigned value from network order to processor order. The macro name can be read "network to host long." #if defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN) #define htons(A) (A) #define htonl(A) (A) #define ntohs(A) (A) #define ntohl(A) (A) #elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN) #define htons(A) ((((uint16)(A) & 0xff00) >> 8) | (((uint16)(A) & 0x00ff) << 8)) #define htonl(A) ((((uint32)(A) & 0xff000000) >> 24) | (((uint32)(A) & 0x00ff0000) >> 8) | (((uint32)(A) & 0x0000ff00) << 8) | (((uint32)(A) & 0x000000ff) << 24)) #define ntohs htons #define ntohl htohl #else #error "Either BIG_ENDIAN or LITTLE_ENDIAN must be #defined, but not both." #endif 但是如果不是走网络,c语言把结构直接写入了文件,那末java读Little Endian 就麻烦一些,这方面的代码很多。 使用jdk1.4以后的版本, float f = ByteBuffer.wrap( array ).order( ByteOrder.LITTLE_ENDIAN ).getFloat(); 否则就得自己写代码了 package com.mindprod.ledatastream; import java.io.DataOutput; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; /** * <pre> * LEDataOutputStream.java * <p/> * copyright (c) 1998-2007 Roedy Green, * Canadian Mind Products * [withheld] * Victoria, BC Canada [withdrawn] * hel: (250) 361-9093 * mailto:roedyg@mindprod.com * http://mindprod.com * <p/> * Version 1.0 1998 January 6 * <p/> * 1.1 1998 January 7 -officially implements DataInput * <p/> * 1.2 1998 January 9 - add LERandomAccessFile * <p/> * 1.3 1998 August 28 1.4 1998 November 10 - add new address and phone. * <p/> * 1.5 1999 October 8 - use com.mindprod.ledatastream * package name. Very similar to DataOutputStream except it writes little-endian * instead of big-endian binary data. We can't extend DataOutputStream directly * since it has only final methods. This forces us implement LEDataOutputStream * with a DataOutputStream object, and use wrapper methods. * </pre> */ public class LEDataOutputStream implements DataOutput { // ------------------------------ FIELDS ------------------------------ /** * work array for composing output */ byte w[]; /** * to get at big-Endian write methods of DataOutPutStream */ protected DataOutputStream d; // -------------------------- STATIC METHODS -------------------------- /** * Embeds copyright notice * * @return copyright notice */ public static final String getCopyright() { return "LeDataStream 1.7 freeware copyright (c) 1998-2007 Roedy Green, Canadian Mind Products, http://mindprod.com roedyg@mindprod.com"; } // --------------------------- CONSTRUCTORS --------------------------- /** * constructor * * @param out the outputstream we ware to write little endian binary data onto */ public LEDataOutputStream( OutputStream out ) { this.d = new DataOutputStream( out ); w = new byte[8];// work array for composing output } // ------------------------ INTERFACE METHODS ------------------------ // --------------------- Interface DataOutput --------------------- /** * This method writes only one byte, even though it says int (non-Javadoc) * * @inheritDoc * @see java.io.DataOutput#write(int) */ public final synchronized void write( int b ) throws IOException { d.write( b ); } /** * @inheritDoc * @see java.io.DataOutput#write(byte[]) */ public final void write( byte b[] ) throws IOException { d.write( b, 0, b.length ); } /** * @inheritDoc * @see java.io.DataOutput#write(byte[],int,int) */ public final synchronized void write( byte b[], int off, int len ) throws IOException { d.write( b, off, len ); } /** * @inheritDoc * @see java.io.DataOutput#writeBoolean(boolean) */ /* Only writes one byte */ public final void writeBoolean( boolean v ) throws IOException { d.writeBoolean( v ); } // p u r e l y w r a p p e r m e t h o d s // We cannot inherit since DataOutputStream is final. /** * @inheritDoc * @see java.io.DataOutput#writeByte(int) */ public final void writeByte( int v ) throws IOException { d.writeByte( v ); } /** * like DataOutputStream.writeShort. also acts as a writeUnsignedShort * * @param v the short you want written in little endian binary format * * @throws IOException * @inheritDoc */ public final void writeShort( int v ) throws IOException { w[ 0 ] = (byte) v; w[ 1 ] = (byte) ( v >> 8 ); d.write( w, 0, 2 ); } /** * like DataOutputStream.writeChar. Note the parm is an int even though this * as a writeChar * * @param v * * @inheritDoc */ public final void writeChar( int v ) throws IOException { // same code as writeShort w[ 0 ] = (byte) v; w[ 1 ] = (byte) ( v >> 8 ); d.write( w, 0, 2 ); } /** * like DataOutputStream.writeInt. * * @param v * * @throws IOException * @inheritDoc */ public final void writeInt( int v ) throws IOException { w[ 0 ] = (byte) v; w[ 1 ] = (byte) ( v >> 8 ); w[ 2 ] = (byte) ( v >> 16 ); w[ 3 ] = (byte) ( v >> 24 ); d.write( w, 0, 4 ); } /** * like DataOutputStream.writeLong. * * @param v * * @throws IOException * @inheritDoc */ public final void writeLong( long v ) throws IOException { w[ 0 ] = (byte) v; w[ 1 ] = (byte) ( v >> 8 ); w[ 2 ] = (byte) ( v >> 16 ); w[ 3 ] = (byte) ( v >> 24 ); w[ 4 ] = (byte) ( v >> 32 ); w[ 5 ] = (byte) ( v >> 40 ); w[ 6 ] = (byte) ( v >> 48 ); w[ 7 ] = (byte) ( v >> 56 ); d.write( w, 0, 8 ); } /** * like DataOutputStream.writeFloat. * * @inheritDoc */ public final void writeFloat( float v ) throws IOException { writeInt( Float.floatToIntBits( v ) ); } /** * like DataOutputStream.writeDouble. * * @inheritDoc */ public final void writeDouble( double v ) throws IOException { writeLong( Double.doubleToLongBits( v ) ); } /** * @inheritDoc * @see java.io.DataOutput#writeBytes(java.lang.String) */ public final void writeBytes( String s ) throws IOException { d.writeBytes( s ); } /** * like DataOutputStream.writeChars, flip each char. * * @inheritDoc */ public final void writeChars( String s ) throws IOException { int len = s.length(); for ( int i = 0; i < len; i++ ) { writeChar( s.charAt( i ) ); } }// end writeChars /** * @inheritDoc * @see java.io.DataOutput#writeUTF(java.lang.String) */ public final void writeUTF( String str ) throws IOException { d.writeUTF( str ); } // -------------------------- OTHER METHODS -------------------------- // L I T T L E E N D I A N W R I T E R S // Little endian methods for multi-byte numeric types. // Big-endian do fine for single-byte types and strings. /** * @throws IOException */ public final void close() throws IOException { d.close(); } // DataOutputStream /** * @throws IOException */ public void flush() throws IOException { d.flush(); } /** * @return bytes written so far in the stream. Note this is a int, not a * long as you would exect. This because the underlying * DataInputStream has a design flaw. */ public final int size() { return d.size(); } }// end LEDataOutputStream package com.mindprod.ledatastream; import java.io.DataInput; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; /** * LEDataInputStream.java copyright (c) 1998-2007 Roedy Green, Canadian Mind * Products [withheld] Victoria, BC Canada [withdrawn] tel: (250) * 361-9093 mailto:roedyg@mindprod.com http://mindprod.com Version 1.0 1998 * January 6 1.1 1998 January 7 - officially implements DataInput 1.2 1998 * January 9 - add LERandomAccessFile 1.3 1998 August 27 - fix bug, readFully * instead of read. 1.4 1998 November 10 - add address and phone. 1.5 1999 * October 8 - use com.mindprod.ledatastream package name. 1.6 2005-06-13 - made * readLine deprecated Very similar to DataInputStream except it reads * little-endian instead of big-endian binary data. We can't extend * DataInputStream directly since it has only final methods, though * DataInputStream itself is not final. This forces us implement * LEDataInputStream with a DataInputStream object, and use wrapper methods. */ public class LEDataInputStream implements DataInput { // ------------------------------ FIELDS ------------------------------ /** * work array for buffering input */ byte w[]; /** * to get at the big-Endian methods of a basic DataInputStream */ protected DataInputStream d; /** * to get at the a basic readBytes method */ protected InputStream in; // -------------------------- STATIC METHODS -------------------------- /** * Embeds copyright notice * * @return copyright notice */ public static final String getCopyright() { return "LeDataStream 1.7 freeware copyright (c) 1998-2007 Roedy Green, Canadian Mind Products, http://mindprod.com roedyg@mindprod.com"; } /** * Note. This is a STATIC method! * * @param in stream to read UTF chars from (endian irrelevant) * * @return string from stream * * @throws IOException */ public final static String readUTF( DataInput in ) throws IOException { return DataInputStream.readUTF( in ); } // --------------------------- CONSTRUCTORS --------------------------- // i n s t a n c e v a r i a b l e s /** * constructor * * @param in binary inputstream of little-endian data. */ public LEDataInputStream( InputStream in ) { this.in = in; this.d = new DataInputStream( in ); w = new byte[8]; } // ------------------------ INTERFACE METHODS ------------------------ // --------------------- Interface DataInput --------------------- /** * @inheritDoc * @see java.io.DataInput#readFully(byte[]) */ public final void readFully( byte b[] ) throws IOException { d.readFully( b, 0, b.length ); } /** * @inheritDoc * @see java.io.DataInput#readFully(byte[],int,int) */ public final void readFully( byte b[], int off, int len ) throws IOException { d.readFully( b, off, len ); } /** * See the general contract of the <code>skipBytes</code> method of * <code>DataInput</code>. * <p/> * Bytes for this operation are read from the contained input stream. * * @param n the number of bytes to be skipped. * * @return the actual number of bytes skipped. * * @throws IOException if an I/O error occurs. */ public final int skipBytes( int n ) throws IOException { return d.skipBytes( n ); } /** * only reads on byte * * @see java.io.DataInput#readBoolean() */ public final boolean readBoolean() throws IOException { return d.readBoolean(); } /** * @inheritDoc * @see java.io.DataInput#readByte() */ public final byte readByte() throws IOException { return d.readByte(); } /** * note: returns an int, even though says Byte (non-Javadoc) * * @inheritDoc * @see java.io.DataInput#readUnsignedByte() */ public final int readUnsignedByte() throws IOException { return d.readUnsignedByte(); } // L I T T L E E N D I A N R E A D E R S // Little endian methods for multi-byte numeric types. // Big-endian do fine for single-byte types and strings. /** * like DataInputStream.readShort except little endian. * * @return little endian binary short from stream * * @throws IOException */ public final short readShort() throws IOException { d.readFully( w, 0, 2 ); return (short) ( ( w[ 1 ] & 0xff ) << 8 | ( w[ 0 ] & 0xff ) ); } /** * like DataInputStream.readUnsignedShort except little endian. Note, * returns int even though it reads a short. * * @return little-endian int from the stream * * @throws IOException */ public final int readUnsignedShort() throws IOException { d.readFully( w, 0, 2 ); return ( ( w[ 1 ] & 0xff ) << 8 | ( w[ 0 ] & 0xff ) ); } /** * like DataInputStream.readChar except little endian. * * @return little endian 16-bit unicode char from the stream * * @throws IOException */ public final char readChar() throws IOException { d.readFully( w, 0, 2 ); return (char) ( ( w[ 1 ] & 0xff ) << 8 | ( w[ 0 ] & 0xff ) ); } /** * like DataInputStream.readInt except little endian. * * @return little-endian binary int from the datastream * * @throws IOException */ public final int readInt() throws IOException { d.readFully( w, 0, 4 ); return ( w[ 3 ] ) << 24 | ( w[ 2 ] & 0xff ) << 16 | ( w[ 1 ] & 0xff ) << 8 | ( w[ 0 ] & 0xff ); } /** * like DataInputStream.readLong except little endian. * * @return little-endian binary long from the datastream * * @throws IOException */ public final long readLong() throws IOException { d.readFully( w, 0, 8 ); return (long) ( w[ 7 ] ) << 56 | /* long cast needed or shift done modulo 32 */ (long) ( w[ 6 ] & 0xff ) << 48 | (long) ( w[ 5 ] & 0xff ) << 40 | (long) ( w[ 4 ] & 0xff ) << 32 | (long) ( w[ 3 ] & 0xff ) << 24 | (long) ( w[ 2 ] & 0xff ) << 16 | (long) ( w[ 1 ] & 0xff ) << 8 | (long) ( w[ 0 ] & 0xff ); } /** * like DataInputStream.readFloat except little endian. * * @return little endian IEEE float from the datastream * * @throws IOException */ public final float readFloat() throws IOException { return Float.intBitsToFloat( readInt() ); } /** * like DataInputStream.readDouble except little endian. * * @return little endian IEEE double from the datastream * * @throws IOException */ public final double readDouble() throws IOException { return Double.longBitsToDouble( readLong() ); } /** * @return a rough approximation of the 8-bit stream as a 16-bit unicode * string * * @throws IOException * @deprecated This method does not properly convert bytes to characters. * Use a Reader instead with a little-endian encoding. */ public final String readLine() throws IOException { return d.readLine(); } /** * @inheritDoc */ public final String readUTF() throws IOException { return d.readUTF(); } // -------------------------- OTHER METHODS -------------------------- /** * @throws IOException */ public final void close() throws IOException { d.close(); } // InputStream // p u r e l y w r a p p e r m e t h o d s // We can't simply inherit since dataInputStream is final. /** * Watch out, read may return fewer bytes than requested. * * @param b where the bytes go * @param off offset in buffer, not offset in file. * @param len count of bytes ot ade * * @return how many bytes read * * @throws IOException */ public final int read( byte b[], int off, int len ) throws IOException { // For efficiency, we avoid one layer of wrapper return in.read( b, off, len ); } }// end class LEDataInputStream java io的代码 /* * @(#)LittleEndianOutputStream.java 1.0.1 99/05/19 * * Copyright 1998, 1999 Elliotte Rusty Harold * */ package com.macfaq.io; import java.io.*; /** * A little endian output stream writes primitive Java numbers * and characters to an output stream in a little endian format. * The standard java.io.DataOutputStream class which this class * imitates uses big-endian integers. * * @author Elliotte Rusty Harold * @version 1.0.1, 19 May 1999 * @see com.macfaq.io.LittleEndianInputStream * @see java.io.DataOutputStream */ public class LittleEndianOutputStream extends FilterOutputStream { /** * The number of bytes written so far to the little endian output stream. */ protected int written; /** * Creates a new little endian output stream and chains it to the * output stream specified by the out argument. * * @param out the underlying output stream. * @see java.io.FilterOutputStream#out */ public LittleEndianOutputStream(OutputStream out) { super(out); } /** * Writes the specified byte value to the underlying output stream. * * @param b the <code>byte</code> value to be written. * @exception IOException if the underlying stream throws an IOException. */ public synchronized void write(int b) throws IOException { out.write(b); written++; } /** * Writes <code>length</code> bytes from the specified byte array * starting at <code>offset</code> to the underlying output stream. * * @param data the data. * @param offset the start offset in the data. * @param length the number of bytes to write. * @exception IOException if the underlying stream throws an IOException. */ public synchronized void write(byte[] data, int offset, int length) throws IOException { out.write(data, offset, length); written += length; } /** * Writes a <code>boolean</code> to the underlying output stream as * a single byte. If the argument is true, the byte value 1 is written. * If the argument is false, the byte value <code>0</code> in written. * * @param b the <code>boolean</code> value to be written. * @exception IOException if the underlying stream throws an IOException. */ public void writeBoolean(boolean b) throws IOException { if (b) this.write(1); else this.write(0); } /** * Writes out a <code>byte</code> to the underlying output stream * * @param b the <code>byte</code> value to be written. * @exception IOException if the underlying stream throws an IOException. */ public void writeByte(int b) throws IOException { out.write(b); written++; } /** * Writes a two byte <code>short</code> to the underlying output stream in * little endian order, low byte first. * * @param s the <code>short</code> to be written. * @exception IOException if the underlying stream throws an IOException. */ public void writeShort(int s) throws IOException { out.write(s & 0xFF); out.write((s >>> 8) & 0xFF); written += 2; } /** * Writes a two byte <code>char</code> to the underlying output stream * in little endian order, low byte first. * * @param c the <code>char</code> value to be written. * @exception IOException if the underlying stream throws an IOException. */ public void writeChar(int c) throws IOException { out.write(c & 0xFF); out.write((c >>> 8) & 0xFF); written += 2; } /** * Writes a four-byte <code>int</code> to the underlying output stream * in little endian order, low byte first, high byte last * * @param i the <code>int</code> to be written. * @exception IOException if the underlying stream throws an IOException. */ public void writeInt(int i) throws IOException { out.write(i & 0xFF); out.write((i >>> 8) & 0xFF); out.write((i >>> 16) & 0xFF); out.write((i >>> 24) & 0xFF); written += 4; } /** * Writes an eight-byte <code>long</code> to the underlying output stream * in little endian order, low byte first, high byte last * * @param l the <code>long</code> to be written. * @exception IOException if the underlying stream throws an IOException. */ public void writeLong(long l) throws IOException { out.write((int) l & 0xFF); out.write((int) (l >>> 8) & 0xFF); out.write((int) (l >>> 16) & 0xFF); out.write((int) (l >>> 24) & 0xFF); out.write((int) (l >>> 32) & 0xFF); out.write((int) (l >>> 40) & 0xFF); out.write((int) (l >>> 48) & 0xFF); out.write((int) (l >>> 56) & 0xFF); written += 8; } /** * Writes a 4 byte Java float to the underlying output stream in * little endian order. * * @param f the <code>float</code> value to be written. * @exception IOException if an I/O error occurs. */ public final void writeFloat(float f) throws IOException { this.writeInt(Float.floatToIntBits(f)); } /** * Writes an 8 byte Java double to the underlying output stream in * little endian order. * * @param d the <code>double</code> value to be written. * @exception IOException if an I/O error occurs. */ public final void writeDouble(double d) throws IOException { this.writeLong(Double.doubleToLongBits(d)); } /** * Writes a string to the underlying output stream as a sequence of * bytes. Each character is written to the data output stream as * if by the <code>writeByte()</code> method. * * @param s the <code>String</code> value to be written. * @exception IOException if the underlying stream throws an IOException. * @see java.io.LittleEndianOutputStream#writeByte(int) * @see java.io.LittleEndianOutputStream#out */ public void writeBytes(String s) throws IOException { int length = s.length(); for (int i = 0; i < length; i++) { out.write((byte) s.charAt(i)); } written += length; } /** * Writes a string to the underlying output stream as a sequence of * characters. Each character is written to the data output stream as * if by the <code>writeChar</code> method. * * @param s a <code>String</code> value to be written. * @exception IOException if the underlying stream throws an IOException. * @see java.io.LittleEndianOutputStream#writeChar(int) * @see java.io.LittleEndianOutputStream#out */ public void writeChars(String s) throws IOException { int length = s.length(); for (int i = 0; i < length; i++) { int c = s.charAt(i); out.write(c & 0xFF); out.write((c >>> 8) & 0xFF); } written += length * 2; } /** * Writes a string of no more than 65,535 characters * to the underlying output stream using UTF-8 * encoding. This method first writes a two byte short * in <b>big</b> endian order as required by the * UTF-8 specification. This gives the number of bytes in the * UTF-8 encoded version of the string, not the number of characters * in the string. Next each character of the string is written * using the UTF-8 encoding for the character. * * @param s the string to be written. * @exception UTFDataFormatException if the string is longer than * 65,535 characters. * @exception IOException if the underlying stream throws an IOException. */ public void writeUTF(String s) throws IOException { int numchars = s.length(); int numbytes = 0; for (int i = 0 ; i < numchars ; i++) { int c = s.charAt(i); if ((c >= 0x0001) && (c <= 0x007F)) numbytes++; else if (c > 0x07FF) numbytes += 3; else numbytes += 2; } if (numbytes > 65535) throw new UTFDataFormatException(); out.write((numbytes >>> 8) & 0xFF); out.write(numbytes & 0xFF); for (int i = 0 ; i < numchars ; i++) { int c = s.charAt(i); if ((c >= 0x0001) && (c <= 0x007F)) { out.write(c); } else if (c > 0x07FF) { out.write(0xE0 | ((c >> 12) & 0x0F)); out.write(0x80 | ((c >> 6) & 0x3F)); out.write(0x80 | (c & 0x3F)); written += 2; } else { out.write(0xC0 | ((c >> 6) & 0x1F)); out.write(0x80 | (c & 0x3F)); written += 1; } } written += numchars + 2; } /** * Returns the number of bytes written to this little endian output stream. * (This class is not thread-safe with respect to this method. It is * possible that this number is temporarily less than the actual * number of bytes written.)
|