Domanda

Da un modo efficiente di suddivisione di un testo in blocchi di 1024 byte in Java? Se v'è più di un chunk l'intestazione (stringa dimensione fissa) deve essere ripetuta in tutti blocchi successivi.

È stato utile?

Soluzione

Corde e byte sono due cose completamente diverse, così volendo dividere una stringa in byte è privo di significato come voler dividere un dipinto in versi.

Che cosa è che si vuole realmente fare?

Per la conversione tra stringhe e byte, è necessario specificare una codifica in grado di codificare tutti i caratteri della stringa. A seconda della codifica e dei personaggi, alcuni di essi possono estendersi su più di un byte.

È possibile dividere la stringa in blocchi di 1024 caratteri e codificare quelle come byte, ma poi ogni blocco può essere più di 1024 byte.

In alternativa, è possibile codificare la stringa originale in byte e poi dividere in blocchi di 1024, ma poi si deve fare in modo di aggiungere loro come byte prima che decodifica il tutto in una stringa di nuovo, o si può ottenere caratteri incomprensibili al punti di divisione quando un carattere occupa più di 1 byte.

Se siete preoccupati per l'utilizzo della memoria quando la stringa può essere molto lungo, è necessario utilizzare i flussi (pacchetto java.io) per la it / decodifica e la scissione, al fine di evitare di mantenere i dati in memoria più volte come copie. Idealmente, si dovrebbe evitare di avere la stringa originale in un unico pezzo a tutti e invece utilizzare i flussi di leggerlo in piccoli pezzi da dove lo si ottiene da.

Altri suggerimenti

Ci sono due modi, il digiuno e il modo conservativo memoria. Ma in primo luogo, è necessario sapere quali caratteri sono nella stringa. ASCII? Ci sono dieresi (i caratteri compresi tra 128 e 255) o anche Unicode (s.getChar () restituisce qualcosa di> 256). A seconda di che, è necessario utilizzare una codifica diversa. Se si dispone di dati binari, provare "iso-8859-1" perché sarà conservare i dati nella stringa. Se si dispone di Unicode, prova a "utf-8". Darò per scontato dati binari:

String encoding = "iso-8859-1";

Il modo più veloce:

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

Si noti che la stringa è Unicode, così ogni esigenza carattere due byte. Si dovrà specificare la codifica (non si basano sul "default piattaforma". Questo farà sì che solo il dolore in seguito).

Ora si può leggere in 1024 pezzi utilizzando

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

Questa ha bisogno di circa tre volte di più RAM come la stringa originale.

Una memoria modo più conservativo è quello di scrivere un convertitore che prende uno StringReader e un OutputStreamWriter (che avvolge una ByteArrayOutputStream). Copia byte dal lettore allo scrittore finché il buffer sottostante contiene un blocco di dati:

Quando lo fa, copiare i dati all'uscita reale (anteponendo l'intestazione), copiare i byte aggiuntivi (quali l'UNICODE-> conversione byte può essere generato) ad un buffer temporaneo, chiamare buffer.reset () e scrivere il tampone temperatura al buffer.

Codice simile a questa (non testata):

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

Questo bisogno solo di un paio di kilobyte di RAM.

[EDIT] C'è stata una lunga discussione su dati binari in stringhe nei commenti. Prima di tutto, è perfettamente sicuro per mettere i dati binari in una stringa fino a quando si è attenti durante la creazione e la memorizzazione da qualche parte. Per creare tale stringa, prendere un array di byte [] e:

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

In Java, ISO-8859-1 (a.k.a ISO-Latin1) è un 1: 1 mapping. Questo significa che i byte nella matrice non saranno interpretati in alcun modo. Ora è possibile utilizzare substring () e simili sui dati o cercare con indice, eseguire regexp di su di esso, ecc, ad esempio, trovare la posizione di un 0 byte:

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

Ciò è particolarmente utile se non si conosce la codifica dei dati e vogliono avere uno sguardo prima di alcuni pasticci codec con esso.

Per scrivere i dati da qualche parte, l'operazione inversa è:

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

Non utilizzare mai i metodi predefiniti new String(array) o String.getBytes()! Un giorno, il codice sta per essere eseguito su una piattaforma diversa e si romperà.

Ora il problema di caratteri> 255 nella stringa. Se si utilizza questo metodo, non si potrà mai avere una di esse nelle stringhe. Detto questo, se ce ne fosse per qualche motivo, quindi getBytes () sarebbe lancerà un'eccezione perché non c'è modo di esprimere tutti i caratteri Unicode in ISO-Latin1, così sei al sicuro, nel senso che il codice non mancherà in silenzio.

Qualcuno potrebbe obiettare che questo non è abbastanza sicuro e si dovrebbe mai mescolare byte e stringa. In questo giorno un'epoca, non abbiamo questo lusso. Un sacco di dati non ha informazioni di codifica esplicita (file, ad esempio, non hanno un attributo di "codifica" nello stesso modo in cui dispongono di autorizzazioni di accesso o un nome). XML è uno dei pochi formati che ha informazioni di codifica esplicita e ci sono editor come Emacs o jEdit che utilizzano i commenti per specificare queste informazioni vitali. Ciò significa che, durante l'elaborazione di flussi di byte, si deve sempre sapere in quale codifica sono. A partire da ora, non è possibile scrivere codice che funziona sempre, indipendentemente da dove i dati provengono da.

Anche con XML, è necessario leggere l'intestazione del file come byte per determinare la codifica prima di poter decodificare la carne.

Il punto importante è quello di sedersi e capire quale codifica è stato utilizzato per generare i dati in streaming è necessario elaborare. Se lo fai, sei bravo, se non lo fai, sei condannato. La confusione nasce dal fatto che la maggior parte delle persone non sono consapevoli del fatto che lo stesso byte può significare cose diverse a seconda della codifica o addirittura that v'è più di una codifica. Inoltre, avrebbe aiutato se Sun non aveva introdotto il concetto di "codifica piattaforma predefinita".

Punti importanti per i principianti:

  • C'è più di una codifica (set di caratteri).
  • Non ci sono più personaggi che la lingua inglese usa. Ci sono anche diverse di cifre (ASCII, larghezza, arabo- Indic, bengalese).
  • È necessario sapere quale codifica è stato utilizzato per generare i dati che si stanno elaborando.
  • è necessario sapere quale codifica si dovrebbe usare per scrivere i dati che si stanno elaborando.
  • È necessario conoscere il modo corretto per specificare le informazioni di codifica in modo che il prossimo programma in grado di decodificare l'output (intestazione XML, HTML meta tag, commento speciale codifica, a prescindere).

I giorni di ASCII sono finiti.

Lo so che sono in ritardo, ma ero alla ricerca di una soluzione me e poi trovato la mia risposta come migliore risposta:

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

Esempio :

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

Stavo cercando questo per me stesso, ho bisogno di un enorme pezzo String (quasi 10 MB) da 1 MB. Questo aiuta a pezzo i dati in tempo minimo. (Meno di un secondo).

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

Sì, la maggior parte se non tutti i sopra sarebbe sicuramente lavorare.

Oppure si potrebbe verificare questo progetto che fa proprio questo; solo che è in grado di pezzo non solo stringhe, ma anche di byte array, inputstreams e file.

Dispone di 2 classi: DataChunker e 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());
            }
        };

Il blob nel costruttore Datachunker's costruttore è sia un array di byte, un File o InputStream

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top