Frage

Was ist ein effizienter Weg, um einen String in Stücke von 1024 Bytes in Java zu spalten? Wenn es mehr als ein Chunk ist dann der Header (feste Größe string) muss in allen nachfolgenden Blöcken wiederholt werden.

War es hilfreich?

Lösung

Strings und Bytes sind zwei völlig verschiedene Dinge, so will einen String in Bytes aufgeteilt ist als sinnlos wie will ein Gemälde in Verse spalten.

Was ist es, dass Sie tatsächlich tun wollen?

zwischen Strings und Bytes konvertieren, müssen Sie eine Codierung angeben, der alle Zeichen im String kodieren kann. In Abhängigkeit von der Codierung und die Charaktere können einige von ihnen erstrecken sich mehr als ein Byte.

Sie können entweder teilen Sie die Zeichenfolge in Stücke von 1024 Zeichen und diejenigen, die als Bytes kodieren, aber dann kann jeder Chunk mehr als 1024 Bytes sein.

Sie können auch die Original-Zeichenkette in Bytes kodieren und teilen sie dann in Stücke von 1024, aber dann müssen Sie sicherstellen, dass sie als Bytes anhängen vor der Decodierung das Ganze in einem String wieder oder können Sie nicht interpretierbare Zeichen an die bekommen Split-Punkte, wenn ein Zeichen mehr als 1 Byte umfasst.

Wenn Sie sich über die Speichernutzung Sorgen machen, wenn der String sehr lang sein können, sollten Sie Ströme (java.io Paket), die an der en / Decodierung und Spalten verwenden, um die Daten im Speicher zu vermeiden, halten mehrmals als Kopien. Idealerweise sollten Sie auf alle ursprünglichen String in einem Stück vermeiden, und stattdessen Ströme verwenden Sie es in kleine Stücke zu lesen, wo immer Sie es von zu bekommen.

Andere Tipps

Sie haben zwei Möglichkeiten, die schnellen und die Erinnerung konservative Art und Weise. Aber zuerst müssen Sie wissen, welche Zeichen im String sind. ASCII? Gibt es Umlaute (Zeichen zwischen 128 und 255) oder auch Unicode (s.getChar () gibt etwas> 256). Abhängig davon, müssen Sie eine andere Codierung verwenden. Wenn Sie binäre Daten haben, versuchen Sie „iso-8859-1“, weil es die Daten im String erhalten wird. Wenn Sie Unicode haben, versuchen Sie "utf-8". Ich werde binäre Daten übernehmen:

String encoding = "iso-8859-1";

Der schnellste Weg:

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

Beachten Sie, dass der String Unicode ist, so alle Zeichen braucht zwei Bytes. Sie werden die Codierung angeben müssen (verlassen Sie sich nicht auf die „Plattform default“. Dies wird nur Schmerz später verursachen).

Jetzt können Sie es in 1024 Stücke lesen mit

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

Das muss etwa dreimal so viel RAM wie das Original String.

Ein Speicher konservativer Weg ist, einen Wandler zu schreiben, die eine String und eine Output nimmt (die eine ByteArrayOutputStream wickelt). Kopieren Bytes vom Leser zum Schreiber, bis der zugrunde liegende Puffer ein Datenpaket enthält:

Wenn es nicht, die Daten an die reale Ausgabe kopieren (Voranstellen des Header), kopieren Sie die zusätzlichen Bytes (die Unicode-> Byte Umwandlung erzeugt haben) in einem temporären Puffer, rufen buffer.reset () und schreiben die Temp Puffer zu puffern.

-Code sieht wie folgt aus (ungetestet):

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 ...

Dies muss nur ein paar Kilobyte RAM.

[EDIT] Es hat mich in den Kommentaren eine langwierige Diskussion über binäre Daten in Strings gewesen. Zunächst einmal, es ist absolut sicher binäre Daten in einen String zu setzen, solange Sie vorsichtig sind, wenn es zu schaffen und es irgendwo speichern. So erstellen Sie einen solchen String, nehmen Sie ein byte [] Array und:

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

In Java, ISO-8859-1 (a.k.a ISO-Latin1) ist eine 1: 1-Abbildung. Das heißt, das Bytes in dem Feld wird nicht in irgendeiner Weise interpretiert werden. Jetzt können Sie substring () und dergleichen auf den Daten verwenden oder es mit dem Index, führte regexp auf ihn suchen, etc. Zum Beispiel findet die Position eines 0-Byte:

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

Dies ist besonders nützlich, wenn Sie die Codierung der Daten nicht kennen und einen Blick auf mich vor einigen Codec Verwirrungen mit ihm haben wollen.

, um die Daten irgendwo zu schreiben, der umgekehrte Vorgang ist:

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

Nie den Standardmethoden new String(array) oder String.getBytes() verwenden! Ein Tag, der Code wird auf einer anderen Plattform ausgeführt werden, und es bricht.

Nun ist das Problem der Zeichen> 255 im String. Wenn Sie diese Methode verwenden, werden Sie nicht immer haben keine solche Zeichen in Ihrem Strings. Das heißt, wenn es einen aus irgendeinem Grunde war, dann getBytes () würde eine Ausnahme, weil es keine Möglichkeit gibt, alle Unicode-Zeichen in ISO-Latin1 zum Ausdruck bringen, so dass Sie im Sinne sicher sind, dass der Code nicht stillschweigend fehl.

Man könnte argumentieren, dass dies nicht sicher genug ist und Sie sollten nie Bytes und String mischen. An diesem Tag ein Alter, haben wir nicht diesen Luxus. Viele Daten haben keine explizite Codierung Informationen (Dateien, zum Beispiel keinen „Codierung“ Attribut in der gleichen Art und Weise haben, wie sie die Zugriffsberechtigungen oder einen Namen haben). XML ist eine der wenigen Formate, die explizite Codierung Informationen hat, und es gibt Editoren wie Emacs oder jEdit, die Kommentare und diese lebenswichtige Informationen zu spezifizieren. Dies bedeutet, dass, wenn Ströme von Bytes verarbeiten, müssen Sie immer wissen, in welcher Kodierung sie sind. Ab sofort ist es nicht möglich, Code zu schreiben, die immer funktionieren werden, unabhängig davon, wo die Daten kommen.

Auch mit XML, müssen Sie den Header der Datei lesen, wie die Bytes die Codierung zu bestimmen, bevor Sie das Fleisch dekodieren kann.

Der wichtige Punkt ist, sich zu setzen und herauszufinden, welche Codierung verwendet wurde, die Daten zu erzeugen, streamen Sie verarbeiten müssen. Wenn Sie das tun, du bist gut, wenn Sie dies nicht tun, sind Sie zum Scheitern verurteilt. Die Verwirrung entsteht ausdie Tatsache, dass die meisten Menschen nicht bewusst sind, dass das gleiche Byte verschiedene Dinge in Abhängigkeit von der Codierung kann bedeuten, oder auch, dass es mehr als eine Codierung. Auch wäre es geholfen, wenn Sun hatte nicht den Begriff eingeführt „Plattform Standard-Kodierung.“

Wichtige Punkte für Anfänger:

  • Es gibt mehr als eine Codierung (charset).
  • Es gibt mehr Zeichen als die englische Sprache verwendet. Es gibt sogar mehr Sätze von Ziffern (ASCII, volle Breite, Arabisch- Indic, Bengali).
  • Sie müssen wissen, welche Codierung verwendet wurde, um die Daten zu erzeugen, die Sie verarbeiten.
  • Sie müssen wissen, welche codiert, sollten Sie die Daten schreiben verwenden, um Sie verarbeiten.
  • Sie müssen die richtige Art und Weise kennen diese Codierung Informationen angeben, damit das nächste Programm können Sie Ihre Ausgabe (XML-Header, HTML-Meta-Tag, spezielle Codierung Kommentar, was auch immer) dekodieren.

Die Tage von ASCII sind vorbei.

Ich weiß, dass ich zu spät bin, aber ich war für eine Lösung selbst suchen und dann fand meine Antwort als beste Antwort:

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;
}

Beispiel: :

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

Output :

abced
fghij
klmno
pqrst
uvwxy
z

Ich war dies für mich versuchen, muss ich Brocken eine riesige String (fast 10 MB) von 1 MB. Dies trägt dazu bei chunk die Daten in minimalem Zeitaufwand. (Weniger als eine Sekunde).

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

Ja, die meisten, wenn nicht alle der oben würde auf jeden Fall funktionieren.

Oder Sie könnten überprüfen dieses Projekt, das genau funktioniert das; nur ist es nicht nur Strings Brocken können, aber auch Byte-Arrays, Inputstreams und Dateien.

Es verfügt über 2 Klassen: DataChunker und 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());
            }
        };

Die blob im Konstruktor Datachunker's Konstruktor ist entweder ein Byte-Array, ein File oder InputStream

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top