2009-03-08 1 views
1

Ich versuche, eine UTF8-Zeichenfolge über einen java.nio.ByteBuffer zu lesen. Die Größe ist ein unsinged int, was natürlich Java nicht hat. Ich habe den Wert in eine lange gelesen, so dass ich den Wert habe.Lesen einer UTF-8-Zeichenfolge aus einem ByteBuffer, wobei die Länge ein unsigned int ist

Das nächste Problem, das ich habe, ist, dass ich nicht ein Array von Bytes mit dem langen erstellen kann, und Casting er lange zurück zu einem int wird dazu führen, dass es signiert wird.

Ich versuchte auch mit Limit() auf den Puffer, aber es funktioniert wieder mit Int nicht lange.

Das Besondere, was ich tue, liest die UTF8-Strings aus einer Klassendatei, so dass der Puffer mehr enthält als nur die UTF8-Zeichenfolge.

Irgendwelche Ideen zum Lesen eines UTF8-Strings, der eine mögliche Länge eines unsigned int von einem ByteBuffer hat.

EDIT:

Here is an example of the issue.

SourceDebugExtension_attribute { 
     u2 attribute_name_index; 
     u4 attribute_length; 
     u1 debug_extension[attribute_length]; 
    } 

attribute_name_index 
    The value of the attribute_name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure representing the string "SourceDebugExtension". 

attribute_length 
    The value of the attribute_length item indicates the length of the attribute, excluding the initial six bytes. The value of the attribute_length item is thus the number of bytes in the debug_extension[] item. 

debug_extension[] 
    The debug_extension array holds a string, which must be in UTF-8 format. There is no terminating zero byte. 

    The string in the debug_extension item will be interpreted as extended debugging information. The content of this string has no semantic effect on the Java Virtual Machine. 

also von einem technischen Standpunkt aus gesehen, ist es möglich, eine Zeichenfolge in der Klassendatei zu haben, die die volle u4 ist (ohne Vorzeichen, 4 Byte) in der Länge.

Dies ist kein Problem, wenn die Größe einer UTF8-Zeichenfolge begrenzt ist (ich bin kein UTF8-Experte, also gibt es vielleicht ein solches Limit).

Ich konnte einfach darauf Punt und mit der Realität gehen, dass es nicht geht, eine Zeichenfolge, die lange dauern, ...

Antwort

6

Sofern Ihr Array von Bytes mehr als 2 GB (dem größten positiven Wert eines Java ist int), Sie werden kein Problem mit dem long zurück in eine signierte int haben.

Wenn Ihr Array von Bytes muss in der Länge mehr als 2 GB sein, du bist es falsch zu machen, nicht zuletzt, weil das ist viel mehr als der maximale Standard Heapsize der JVM ...

+1

Sicherlich kann das Array von Bytes länger sein, wenn die Kodierung> 1 Byte/Zeichen ist. String kapselt ein char [] -Array und kein byte [] -Array. –

+0

sicher, es kann länger sein. Es wird aber niemals 2 GB erreichen. – Alnitak

+0

sehe meine Bearbeitung ... die Größe ist überhaupt nicht unter meiner Kontrolle ... – TofuBeer

1

Nachdem int gewonnen unterzeichnet Sei nicht dein Hauptproblem. Angenommen, Sie hatten einen String, der 4 Milliarden lang war. Sie benötigen einen ByteBuffer, der mindestens 4 GB groß ist, ein Byte [], das mindestens 4 GB groß ist. Wenn Sie dies in einen String konvertieren, benötigen Sie mindestens 8 GB (2 Bytes pro Zeichen) und einen StringBuilder, um es zu erstellen. (Mindestens 8 GB) Alles, was Sie brauchen, 24 GB, um 1 String zu verarbeiten. Selbst wenn Sie viel Speicher haben, werden Sie nicht viele Strings dieser Größe bekommen.

Ein anderer Ansatz besteht darin, die Länge als signiert zu behandeln und, falls unsigniert, als einen Fehler zu behandeln, da Sie nicht genügend Speicher haben, um den String in jedem Fall zu verarbeiten. Selbst wenn Sie einen String mit 2 Milliarden (2^31-1) Länge verarbeiten möchten, benötigen Sie 12 GB, um ihn auf diese Weise in einen String zu konvertieren.

1

Java-Arrays verwenden, um eine (Java, dh unterzeichnet) int für den Zugang as per the languge spec, so ist es unmöglich, einen String zu haben (was durch eine char-Array unterstützt wird) länger als Integer.MAX_INT

Aber auch das viel Weg zu viel, um in einem Chunk verarbeitet zu werden - es wird die Performance komplett zunichtemachen und Ihr Programm mit einem OutOfMemoryError auf den meisten Maschinen fehlschlagen lassen, wenn ein ausreichend großer String jemals gefunden wird.

Was Sie tun sollten, ist jede Zeichenfolge in Brocken einer vernünftigen Größe zu verarbeiten, sagen Sie ein paar MBs gleichzeitig. Dann gibt es keine praktische Grenze für die Größe, mit der Sie umgehen können.

0

Ich denke, Sie könnten CharSequence auf einem ByteBuffer implementieren. Das würde es ermöglichen, dass Ihr "String" nicht auf dem Heap erscheint, obwohl die meisten Dienstprogramme, die sich mit Zeichen befassen, tatsächlich einen String erwarten. Und selbst dann ist CharSequence tatsächlich begrenzt. Es erwartet, dass die Größe als int zurückgegeben wird.

(Sie könnten theoretisch eine neue Version von CharSequence erstellen, die die Größe als long zurückgibt, aber dann gibt es in Java nichts, was Ihnen im Umgang mit dieser CharSequence helfen könnte. Vielleicht wäre es nützlich, wenn Sie subSequence(...) implementieren würden eine gewöhnliche CharSequence.)

Verwandte Themen