2017-02-03 1 views
3

Ich habe eine große Textdatei (ca. 20 Millionen Zeilen), die Zeilen im folgende Format hat: Whitespaces, die ich beim Lesen der Datei entfernen mag, kann diese Strings stechend oder schleppendWie trimmen Sie Strings in Java, ohne ein neues Objekt zu erstellen?

<string1>, <string2> 

Jetzt.

Ich verwende derzeit trim() für diesen Zweck, aber da String in Java unveränderlich ist, erstellt trim() ein neues Objekt pro Trim-Operation. Dies führt zu zu viel Verschwendung von Speicher.

Wie kann ich es besser machen?

+3

Bitte zeigen Sie, wie Sie die Datei lesen und dann die Strings aufteilen. –

+1

Sie erkennen, dass nicht verwendete Strings gesammelt werden. Es gibt also keinen wirklichen * Speicher *, sondern nur neu erstellte Objekte (die vom GC effizient gesammelt werden). – Kayaman

+0

Ich bin nicht ganz sicher, aber ich denke, mit [sed] (http://www.grymoire.com/Unix/Sed.html) könnte das Problem lösen –

Antwort

0

Sie können Ihre Zeichenfolge als Zeichenstrom lesen und die Start- und Endposition jedes Tokens aufzeichnen, das Sie analysieren möchten.

Dies erstellt immer noch ein Objekt pro Token, aber wenn Ihre Token relativ lang sind, sind die zwei int Felder, die Ihr Objekt enthält, viel kleiner als die entsprechende Zeichenfolge wäre.

Aber bevor Sie sich auf diese Reise begeben, sollten Sie wahrscheinlich sicherstellen, dass Sie Ihre getrimmten Saiten nicht länger als nötig aufbewahren.

0

Sie Angenommen, haben eine String<string1>, <string2> enthält, und Sie wollen, nur um es zu spalten, ohne vielleicht die Teile Besatz:

String trimmedBetween(String str, int start, int end) { 
    while (start < end && Character.isWhitespace(str.charAt(start)) { 
    ++start; 
    } 

    while (start < end && Character.isWhitespace(str.charAt(end - 1)) { 
    --end; 
    } 

    return str.substring(start, end); 
} 

(Hinweis: Dies ist im Grunde wie String.trim() implementiert ist, nur mit start und end statt 0 und length)

Dann rufen wie:

int commaPos = str.indexOf(','); 
String firstString = trimmedBetween(str, 0, commaPos); 
String secondString = trimmedBetween(str, commaPos + 1, str.length()); 
+0

Ich möchte die Teile, d. H. Die einzelnen Saiten trimmen. –

+0

Warum sollte ich diese Trimmung anstelle der Standard Trimmer verwenden? Das Ziel war, Speicherverschwendung zu vermeiden, aber Sie verwenden den gleichen zusätzlichen Speicher (= Sie geben eine neue Zeichenkette zurück) als das eingebaute 'trim()' – tucuxi

+0

Weil 'String.trim()' nur vom Anfang und vom Ende schneidet die Saite. Dazu müssen Sie die Zeichenfolge aufteilen (ein Array und zwei Strings erstellen) und sie dann trimmen (bis zu zwei weitere Strings). Dieser Ansatz erstellt genau zwei Strings anstelle von 4 Strings und ein Array. –

-1

Ich denke, Sie können die Ergebnisdaten direkt in eine neue Datei schreiben.

String originStr = " xxxxyyyy"; 
for (int i = 0; i < originStr.length(); i++) { 
    if (' ' == originStr.charAt(i)) { 
     continue; 
    } 
    NewFileOutPutStream.write(originStr.charAt(i)); 
} 
+0

Wenn Sie m-thread-Modell verwenden, können Sie Ihre Datei trennen, lassen Sie sie einige Chunk-Datei für logisch sein, und dann oben Methode ist auch gut funktioniert. – Axl

+0

Das Schreiben eines einzelnen Zeichens auf einmal dauert ewig. Sie müssen es puffern. – markbernard

2

Ich wäre überrascht, wenn die unveränderliche String Klasse Probleme verursacht; Die JVM ist sehr effizient und das Ergebnis langjähriger Ingenieursarbeit.

Das heißt, Java bietet eine veränderbare Klasse für die Manipulation von Strings namens StringBuilder. Sie können die Dokumentation here lesen.

Wenn Sie über Threads arbeiten, consider using StringBuffer.

0

Wie Sie bereits bemerkt haben, sind Strings unveränderlich. Die Lösung besteht also darin, String nicht zu verwenden, sondern etwas, das veränderbar ist. StringBuffer ist eine geeignete Klasse.

jedoch String enthält keine Trimmverfahren, so können Sie so etwas wie verwenden:

void trim(StringBuffer sb) { 
    int start = 0; 
    while (sb.length() > start && Character.isWhitespace(sb.charAt(0))) { 
     start++; 
    } 
    sb.delete(0, start - 1); 

    int end = 0; 
    while (sb.length() > end && Character.isWhitespace(sb.charAt(sb.length() - 1))) { 
     end++; 
    } 
    sb.delete(sb.length() - end, sb.length() - 1); 
} 
0

Wenn Sie String vermeiden wollen, dann müssen Sie es selbst behandeln char und StringBuilder verwenden, wie folgt aus:

public class Test { 
    public static void main(String... args) throws Exception { 
     InputStreamReader in = new InputStreamReader(new FileInputStream("<testfile>"), "UTF-8"); 

     char[] buffer = new char[32768]; 
     int read = -1; 
     int index; 
     StringBuilder content = new StringBuilder(); 
     while ((read = in.read(buffer)) > -1) { 
      content.append(buffer, 0, read); 
      index = 0; 
      while (index > -1) { 
       index = content.indexOf("\n"); 
       if (index > -1) { 
        char[] temp = new char[index]; 
        content.getChars(0, index, temp, 0); 
        handleLine(temp); 
        content.replace(0, index + 1, ""); 
       } 
      } 
     } 

     in.close(); 
    } 

    private static void handleLine(char[] line) { 
     StringBuilder content = new StringBuilder().append(line); 
     int start = 0; 
     int end = content.length(); 
     if (end > 0) { 
      char ch = content.charAt(0); 
      while (Character.isWhitespace(content.charAt(start))) { 
       start++; 
       if (end <= start) { 
        break; 
       } 
      } 
      if (start < end) { 
       while (Character.isWhitespace(content.charAt(end - 1))) { 
        end--; 
        if (end <= start) { 
         break; 
        } 
       } 
      } 
     } 

     System.out.println("***" + content.subSequence(start, end) + "***"); 
    } 
} 
0

Wir könnten mit Regex umgehen.

{ 
    String str = "abcd, efgh"; 
    String [] result = str.split("(,\\s)|,"); 
    Arrays.asList(result).forEach(s -> System.out.println(s)); 
    } 
Verwandte Themen