Question

Quel est un moyen efficace de diviser une chaîne en morceaux de 1024 octets en java? S'il y a plus d'un morceau puis l'en-tête (chaîne de taille fixe) doit être répétée dans tous les morceaux suivants.

Était-ce utile?

La solution

Les chaînes et les octets sont deux choses complètement différentes, de sorte vouloir diviser une chaîne en octets est dénuée de sens que de vouloir diviser un tableau en vers.

Qu'est-ce que vous voulez réellement faire?

Pour convertir entre les chaînes et les octets, vous devez spécifier un codage qui peut encoder tous les caractères de la chaîne. Selon le codage et les caractères, certains d'entre eux peuvent couvrir plus d'un octet.

Vous pouvez diviser la chaîne en morceaux de 1024 caractères et encodez ceux sous forme d'octets, mais chaque morceau peut être plus de 1024 octets.

Vous pouvez encoder la chaîne d'origine en octets, puis les diviser en morceaux de 1024, mais vous devez vous assurer de les ajouter sous forme d'octets avant décodage de l'ensemble dans une chaîne à nouveau, ou vous pouvez obtenir des caractères tronqués à la les points de division quand un caractère enjambe plus de 1 octet.

Si vous êtes inquiet sur l'utilisation de la mémoire lorsque la chaîne peut être très longue, vous devez utiliser les flux (paquet de java.io) à l'en / décodage et le fractionnement, afin d'éviter de garder les données en mémoire plusieurs fois copies. Idéalement, vous devriez éviter d'avoir la chaîne d'origine en un seul morceau du tout et au lieu d'utiliser des flux pour lire en petits morceaux où que vous obtenez à partir.

Autres conseils

Vous avez deux façons, la voie rapide et la mémoire conservatrice. Mais d'abord, vous devez savoir ce que les personnages sont dans la chaîne. ASCII? Y at-il trémas (caractères entre 128 et 255) ou même Unicode (s.getChar () retourne quelque chose> 256). En fonction de cela, vous aurez besoin d'utiliser un codage différent. Si vous avez des données binaires, essayez « iso-8859-1 » parce qu'il conservera les données de la chaîne. Si vous avez Unicode, essayez "utf-8". Je suppose que les données binaires:

String encoding = "iso-8859-1";

La façon la plus rapide:

ByteArrayInputStream in = new ByteArrayInputStream (string.getBytes(encoding));

Notez que la chaîne est Unicode, donc tous les besoins de caractères deux octets. Vous devrez spécifier l'encodage (ne comptez pas sur la « plate-forme par défaut ». Cela ne fera que causer de la douleur plus tard).

Maintenant, vous pouvez le lire en 1024 morceaux en utilisant

byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) > 0) { ... }

Il a besoin d'environ trois fois plus de RAM que la chaîne d'origine.

A plus de mémoire façon conservatrice est d'écrire un convertisseur qui prend une StringReader et un OutputStreamWriter (qui enveloppe un ByteArrayOutputStream). Copie octets du lecteur à l'auteur jusqu'à ce que le tampon sous-jacente contient un bloc de données:

Quand il ne, copier les données à la sortie vraie (préfixant l'en-tête), copier les octets supplémentaires (que la conversion à Unicode> octet peut avoir généré) vers une mémoire tampon temporaire, appel buffer.reset () et écrire le tampon temporaire au tampon.

code ressemble à ceci (non testé):

StringReader r = new StringReader (string);
ByteArrayOutputStream buffer = new ByteArrayOutputStream (1024*2); // Twice as large as necessary
OutputStreamWriter w = new OutputStreamWriter  (buffer, encoding);

char[] cbuf = new char[100];
byte[] tempBuf;
int len;
while ((len = r.read(cbuf, 0, cbuf.length)) > 0) {
    w.write(cbuf, 0, len);
    w.flush();
    if (buffer.size()) >= 1024) {
        tempBuf = buffer.toByteArray();
        ... ready to process one chunk ...
        buffer.reset();
        if (tempBuf.length > 1024) {
            buffer.write(tempBuf, 1024, tempBuf.length - 1024);
        }
    }
}
... check if some data is left in buffer and process that, too ...

Il a besoin seulement quelques kilo-octets de RAM.

[EDIT] Il y a eu une longue discussion sur les données binaires dans les chaînes dans les commentaires. Tout d'abord, il est tout à fait sûr de mettre les données binaires dans une chaîne aussi longtemps que vous faites attention lors de la création et le stocker quelque part. Pour créer une telle chaîne, prendre un octet [] tableau et:

String safe = new String (array, "iso-8859-1");

En Java, ISO-8859-1 (a.k.a ISO-Latin1) est un mappage 1: 1. Cela signifie que les octets dans le tableau ne seront pas interprétées en aucune façon. Maintenant, vous pouvez utiliser substring () et autres sur les données ou la recherche avec index, exécutez regexp est sur elle, etc. Par exemple, trouver la position d'un 0 octet:

int pos = safe.indexOf('\u0000');

Ceci est particulièrement utile si vous ne connaissez pas le codage des données et que vous voulez jeter un oeil à certains avant codec salit avec elle.

Pour écrire les données quelque part, l'opération inverse est:

byte [] data = safe.getBytes ( "iso-8859-1");

Ne jamais utiliser les méthodes par défaut ou new String(array) String.getBytes()! Un jour, votre code va être exécuté sur une autre plate-forme et il se brisera.

Maintenant, le problème des caractères> 255 dans la chaîne. Si vous utilisez cette méthode, vous ne serez jamais avoir un tel caractère dans vos cordes. Cela dit, s'il y en avait pour une raison quelconque, getBytes () jetterait une exception parce qu'il n'y a aucun moyen d'exprimer tous les caractères Unicode dans ISO-Latin1, de sorte que vous êtes en sécurité dans le sens que le code ne manquera pas en silence.

Certains diront que cela ne suffit pas sûr et vous ne devez jamais mélanger octets et String. Dans ce jour un âge, on n'a pas ce luxe. Beaucoup de données n'a pas d'informations de codage explicite (fichiers, par exemple, ne dispose pas d'un attribut « encodage » de la même manière qu'ils ont des droits d'accès ou un nom). XML est l'un des rares formats qui a des informations explicites de codage et il y a des éditeurs comme Emacs ou jEdit qui utilisent des commentaires pour préciser ces informations vitales. Cela signifie que, vous devez toujours savoir où ils sont le codage lors du traitement des flux d'octets. À l'heure actuelle, il est impossible d'écrire du code qui fonctionnera toujours, peu importe où les données proviennent.

Même avec XML, vous devez lire l'en-tête du fichier en octets pour déterminer l'encodage avant de pouvoir décoder la viande.

Le point important est de s'asseoir et déterminer quel codage a été utilisé pour générer les flux de données que vous avez à traiter. Si vous faites cela, vous êtes bien, si vous ne le faites pas, vous êtes condamné. La confusion provient du fait que la plupart des gens ne savent pas que le même octet peut signifier différentes choses en fonction de l'encodage ou même that il y a plus d'un codage. , Il aurait également aidé si Sun avait pas introduit la notion de « codage par défaut de la plate-forme. »

Points importants pour les débutants:

Les jours ASCII sont plus.

Je sais que je suis en retard, mais je cherchais une solution moi-même, puis trouvé ma réponse comme meilleure réponse:

private static String chunk_split(String original, int length, String separator) throws IOException {
    ByteArrayInputStream bis = new ByteArrayInputStream(original.getBytes());
    int n = 0;
    byte[] buffer = new byte[length];
    String result = "";
    while ((n = bis.read(buffer)) > 0) {
        for (byte b : buffer) {
            result += (char) b;
        }
        Arrays.fill(buffer, (byte) 0);
        result += separator;
    }
    return result;
}

Exemple :

public static void main(String[] args) throws IOException{
       String original = "abcdefghijklmnopqrstuvwxyz";
       System.out.println(chunk_split(original,5,"\n"));
}

Sortie :

abced
fghij
klmno
pqrst
uvwxy
z

Je tentais pour moi-même, je dois un énorme morceau String (près de 10 Mo) par 1 MB. Cela aide morceau les données en quantité minimum de temps. (Moins d'une seconde).

private static ArrayList<String> chunkLogMessage(String logMessage) throws Exception {
    ArrayList<String> messages = new ArrayList<>();
    if(logMessage.getBytes().length > CHUNK_SIZE) {
        Log.e("chunk_started", System.currentTimeMillis()+"");
        byte[] buffer = new byte[CHUNK_SIZE];
        int start = 0, end = buffer.length;
        long remaining = logMessage.getBytes().length;
        ByteArrayInputStream inputStream = new ByteArrayInputStream(logMessage.getBytes());
        while ((inputStream.read(buffer, start, end)) != -1){
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            outputStream.write(buffer, start, end);
            messages.add(outputStream.toString("UTF-8"));
            remaining = remaining - end;
            if(remaining <= end){
                end = (int) remaining;
            }
        }
        Log.e("chunk_ended", System.currentTimeMillis()+"");
        return messages;
    }
    messages.add(logMessage);
    return messages;
}

Logcat:

22:08:00.262 3382-3425/com.sample.app E/chunk_started: 1533910080261
22:08:01.228 3382-3425/com.sample.app E/chunk_ended: 1533910081228
22:08:02.468 3382-3425/com.sample.app E/chunk_started: 1533910082468
22:08:03.478 3382-3425/com.sample.app E/chunk_ended: 1533910083478
22:09:19.801 3382-3382/com.sample.app E/chunk_started: 1533910159801
22:09:20.662 3382-3382/com.sample.app E/chunk_ended: 1533910160662

Oui, la plupart sinon tous les aurait certainement travailler dessus.

Ou vous pouvez consulter ce projet qui fait exactement cela; seulement il est capable de morceau pas seulement des chaînes, mais aussi octet tableaux, InputStreams et fichiers.

Il a 2 classes: et DataChunker StringChunker


DataChunker chunker = new DataChunker(8192, blob) {
@Override 
public void chunkFound(byte[] foundChunk, int bytesProcessed) {
//process chunk here
}
@Override 
public void chunksExhausted(int bytesProcessed) { 
//called when all the blocks have been exhausted
} 
};

String blob = "Experience is wasted if history does not repeat itself...Gbemiro Jiboye";

 final StringBuilder builder = new StringBuilder();
        StringChunker chunker = new StringChunker(4, blob) {
            @Override
            public void chunkFound(String foundChunk, int bytesProcessed) {
                builder.append(foundChunk);
                System.out.println("Found: "+foundChunk+", bytesProcessed: "+bytesProcessed+" bytes");
            }

            @Override
            public void chunksExhausted(int bytesProcessed) {
                System.out.println("Processed all of: "+bytesProcessed+" bytes. Rebuilt string is: "+builder.toString());
            }
        };

Le blob dans le constructeur Datachunker's constructeur est soit un tableau d'octets, un File ou un InputStream

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top