问题
The String(byte[] bytes)
constructor and String.getBytes()
method are not implemented by GWT JRE emulation String class.
Does anybody know of an implementation? I do not want to use char[]
, But it seems like there is no other solution.
回答1:
If you create large arrays in Chrome, you might run into a Uncaught RangeError: Maximum call stack size exceeded exception. The code from LINEMAN78 can be modified to use a StringBuilder, which avoids this issue.
public static String getString(byte[] bytes, int bytesPerChar)
{
if (bytes == null) throw new IllegalArgumentException("bytes cannot be null");
if (bytesPerChar < 1) throw new IllegalArgumentException("bytesPerChar must be greater than 1");
final int length = bytes.length / bytesPerChar;
final StringBuilder retValue = new StringBuilder();
for (int i = 0; i < length; i++)
{
char thisChar = 0;
for (int j = 0; j < bytesPerChar; j++)
{
int shift = (bytesPerChar - 1 - j) * 8;
thisChar |= (0x000000FF << shift) & (((int) bytes[i * bytesPerChar + j]) << shift);
}
retValue.append(thisChar);
}
return retValue.toString();
}
回答2:
The following code should work, just specify the number of bytes per character.
public class GwtPlayground implements EntryPoint
{
static final Logger logger = Logger.getLogger("");
@Override
public void onModuleLoad()
{
VerticalPanel loggerArea = new VerticalPanel();
logger.addHandler(new HasWidgetsLogHandler(loggerArea));
RootPanel.get().add(loggerArea);
String original = new String("A" + "\uffea" + "\u00f1" + "\u00fc" + "C");
logger.info("original = " + original);
byte[] utfBytes = getBytes(original, 2);
String roundTrip = getString(utfBytes, 2);
logger.info("roundTrip = " + roundTrip);
}
public static byte[] getBytes(String string, int bytesPerChar)
{
char[] chars = string.toCharArray();
byte[] toReturn = new byte[chars.length * bytesPerChar];
for (int i = 0; i < chars.length; i++)
{
for (int j = 0; j < bytesPerChar; j++)
toReturn[i * bytesPerChar + j] = (byte) (chars[i] >>> (8 * (bytesPerChar - 1 - j)));
}
return toReturn;
}
public static String getString(byte[] bytes, int bytesPerChar)
{
char[] chars = new char[bytes.length / bytesPerChar];
for (int i = 0; i < chars.length; i++)
{
for (int j = 0; j < bytesPerChar; j++)
{
int shift = (bytesPerChar - 1 - j) * 8;
chars[i] |= (0x000000FF << shift) & (((int) bytes[i * bytesPerChar + j]) << shift);
}
}
return new String(chars);
}
}
As @Per Wiklander pointed out, this doesn't truely support UTF-8. Here is a true UTF-8 decoder ported from C here
private static class UTF8Decoder
{
final byte[] the_input;
int the_index, the_length;
protected UTF8Decoder( byte[] bytes )
{
super();
this.the_input = bytes;
this.the_index = 0;
this.the_length = bytes.length;
}
/*
Get the next byte. It returns UTF8_END if there are no more bytes.
*/
int get()
{
int c;
c = the_input[the_index] & 0xFF;
the_index += 1;
return c;
}
/*
Get the 6-bit payload of the next continuation byte.
Return UTF8_ERROR if it is not a contination byte.
*/
int cont()
{
int c = get();
if( (c & 0xC0) == 0x80 )
return (c & 0x3F);
else
throw new IllegalArgumentException( "Failed to pass strict UTF-8" );
}
CharSequence getStringUTF8()
{
StringBuilder sb = new StringBuilder( the_input.length ); // allocate a maximum size
while( the_index < the_length )
{
int c; /* the first byte of the character */
int r; /* the result */
c = get();
/*
Zero continuation (0 to 127)
*/
if( (c & 0x80) == 0 )
{
sb.append( (char) c );
}
/*
One continuation (128 to 2047)
*/
else if( (c & 0xE0) == 0xC0 )
{
int c1 = cont();
if( c1 >= 0 )
{
r = ((c & 0x1F) << 6) | c1;
if( r >= 128 )
sb.append( (char) r );
else
throw new IllegalArgumentException();
}
}
/*
Two continuation (2048 to 55295 and 57344 to 65535)
*/
else if( (c & 0xF0) == 0xE0 )
{
int c1 = cont();
int c2 = cont();
if( (c1 | c2) >= 0 )
{
r = ((c & 0x0F) << 12) | (c1 << 6) | c2;
if( r >= 2048 && (r < 55296 || r > 57343) )
sb.append( (char) r );
else
throw new IllegalArgumentException();
}
}
/*
Three continuation (65536 to 1114111)
*/
else if( (c & 0xF8) == 0xF0 )
{
int c1 = cont();
int c2 = cont();
int c3 = cont();
if( (c1 | c2 | c3) >= 0 )
sb.append( (char) ((((c & 0x0F) << 18) | (c1 << 12) | (c2 << 6) | c3) + 65536) ); // TODO this might not work as it is being cast to a char
}
else
throw new IllegalArgumentException( "Failed strict UTF8 parsing" );
}
return sb;
}
}
回答3:
Good question. I didn't realize it before.
as far as I know there is only 2 main method that convert byte array to String
- You mentioned it
- The fantastic way with java.io package that you can't use it on client-side
Here is mine implementation. I think it may be helpful to you
public static String convertByteArrayToString(byte[] byteArray) {
String s = "";
for (int i = 0; i < byteArray.length; i++) {
s += (char) (byteArray[i]);
}
return s;
}
You can test it :
byte[] byteArray = new byte[] { 87, 79, 87, 46, 46, 46 };
System.out.println(convertByteArrayToString(byteArray));
System.out.println(new String(byteArray));
来源:https://stackoverflow.com/questions/4584998/how-to-convert-a-byte-array-to-a-string-and-string-to-a-byte-array-with-gwt