D'obtenir la taille de la Chaîne w/ encodage en octets sans avoir à les convertir byte[]
J'ai une situation où j'ai besoin de savoir la taille d'un String
/encodage paire, en octets, mais ne peut pas utiliser le getBytes()
méthode parce que 1) la String
est très grand et la duplication de la String
dans un byte[]
tableau serait d'utiliser une grande quantité de mémoire, mais plus au point 2) getBytes()
alloue un byte[]
tableau basé sur la longueur de la String
* le maximum d'octets par caractère. Donc, si j'ai un String
avec 1,5 B de caractères et encodage UTF-16, getBytes()
vais essayer d'allouer un tableau 3 go et ne parviennent pas, comme les tableaux sont limités à 2^32 - X octets (X est la version Java spécifique).
Donc - est-il possible de calculer la taille en octets d'un String
/encodage paire directement à partir de la String
objet?
Mise à JOUR:
Voici un travail de mise en œuvre de jtahlborn réponse:
private class CountingOutputStream extends OutputStream {
int total;
@Override
public void write(int i) {
throw new RuntimeException("don't use");
}
@Override
public void write(byte[] b) {
total += b.length;
}
@Override public void write(byte[] b, int offset, int len) {
total += len;
}
}
Je voudrais ajouter qu'il est également la personne à charge sur le point de code ("caractères"), l'encodage. Par exemple, en UTF-16, certains points de code utilise 1 code de l'unité, d'autres utilisations 2 (une unité de code est de 16 bits). UTF-8 peut prendre de 1 à 4 octets par caractère.
Désolé si je suis dense, mais oui, votre commentaire est le point de la question: étant donné une Chaîne et un encodage, combien d'octets ne codant pour la Chaîne? En relisant la question, qui semble assez clair pour moi: avez - vous des suggestions de reformulation?
le commentaire ci-dessus s'applique à votre commentaire ainsi, au meilleur de ma capacité à dire.
getByte
ne pas créer un tableau plus grand, alors il doit être. Il crée un tableau de la bonne taille pour la chaîne. Il n'a pas crée un tableau de longueur "longueur de la Chaîne * le maximum d'octets par caractère". Et string.length()
ne retourne pas le nombre de caractères dans une chaîne, elle renvoie le nombre d'unités de code. Pour l'UTF-16, un code de l'unité est de 16 bits, et le nombre d'unités de code par caractère est 1 ou 2, cela dépend du caractère. Donc, soit je ne comprends pas votre second point de votre question ou de votre hypothèse n'est pas correcte.OriginalL'auteur elhefe | 2013-11-08
Vous devez vous connecter pour publier un commentaire.
Simple, il suffit de l'écrire sur un mannequin flux de sortie:
ce n'est pas seulement simple, mais probablement aussi vite que les autres "complexe" des réponses.
votre version de la compilation, mais c'est incorrect. vous ne voulez pas utiliser le décalage dans le calcul.
Oups, corrigé. Apparemment, seuls les write(byte[]) méthode a été utilisée par mes tests.
pour
int
, vous incrémenter une seule fois. Avez-vous supposer qu'un seul chiffre peut être passé à cette méthode? Je pense qu'il devrait être le nombre de chiffres qui doivent être ajoutés à_total
. Pouvez-vous préciserchanger
_total
à unlong
serait suffisant.OriginalL'auteur jtahlborn
Ici est apparemment un travail de mise en œuvre:
La sortie est:
Dans la pratique, je voudrais augmenter
ENCODE_CHUNK
à 10MChars.Probablement légèrement moins efficace que le brettw de la réponse, mais plus simple à mettre en œuvre.
OutputStreamWriter
de l'autre solution sera également effectuer un codage réel de l'opération dans une mémoire tampon, avant de passer à l'CountingOutputStream
. Le seul inconvénient est que votre solution alloue de nouvellesByteBuffer
instances. Lorsque vous résoudre que par la mise en œuvre de la norme d'encodage de la boucle, vous avez de la manière la plus rapide possible (générique) solution. Voir cette réponse pour un bon marché de calcul spécifiquement pour l'UTF-8.OriginalL'auteur elhefe
Le même à l'aide de apache commons bibliothèques:
OriginalL'auteur 30thh
Ok, c'est très brut. Je l'avoue, mais ce genre de choses est caché par la JVM, nous avons donc de creuser un peu. Et transpirer un peu.
Tout d'abord, nous voulons que le réel char[] que le dos d'une Chaîne sans en faire une copie. Pour ce faire, nous devons utiliser la réflexion pour obtenir le champ "valeur":
Ensuite, vous devez mettre en œuvre une sous-classe de
java.nio.ByteBuffer
. Quelque chose comme:Ignorer tous les getters, de mettre en œuvre tous les mettre méthodes comme
put(byte)
etputChar(char)
etc. À l'intérieur de quelque chose commeput(byte)
, incrémenter longueur par 1, à l'intérieur deput(byte[])
incrément longueur par la longueur du tableau. Pour l'obtenir? Tout ce qui est à faire, vous ajoutez de la taille de ce qu'il est à longueur. Mais vous n'êtes pas tout stocker dans votreByteBuffer
, vous êtes juste de comptage et de jeter, donc aucun espace n'est prise. Si vous point d'arrêt de laput
méthodes, vous pouvez probablement trouver lesquels vous avez réellement besoin de mettre en œuvre.putFloat(float)
est probablement pas utilisé, par exemple.Maintenant pour la grande finale, mettant tous ensemble:
CharBuffer.wrap(CharSequence)
avec laString
lui-même. utiliser lechar[]
de laString
sans copier (au moins dans Oracle JDK 7 Update 21).Oh joli! Je ne le savais pas.
@JoachimSauer dit il y a longtemps, il n'est pas nécessaire pour cette Réflexion hack, donc pourquoi est-ce répondre à commencer toujours avec elle? Départ avec Java 9, on va à l'échec comme le tableau interne n'est pas un
char[]
(laissant de côté l'alternative JRE implémentations où il n'ont même plus tôt). En outre, il est étrange de boucle surgetDeclaredFields()
au lieu de simplement appelergetDeclaredField("value")
, mais de toute façon. L'idée principale de votre réponse, la création d'une sous-classe deByteBuffer
dans la demande, c'est impossible.OriginalL'auteur brettw