2017-02-03 45 views
3

У меня есть большой текстовый файл (около 20 миллионов строк), которая имеет строки в следующем формате:Как обрезать строки в java без создания нового объекта?

<string1>, <string2> 

Теперь эти строки могут быть конечные или ведущие пробельные, которые я хочу, чтобы удалить при чтении файла.

В настоящее время я использую для этой цели trim(), но поскольку String в Java неизменен, trim() создает новый объект на операцию триммера. Это приводит к слишком большому количеству потерь памяти.

Как я могу сделать это лучше?

+3

Пожалуйста, покажите, как вы читаете файл, а затем разделяете строки. –

+1

Вы понимаете, что все неиспользуемые строки собраны, поэтому нет реального * отхода * памяти, только новых созданных объектов (которые эффективно собираются GC). – Kayaman

+0

Я не совсем уверен, но я думаю, что использование [sed] (http://www.grymoire.com/Unix/Sed.html) может решить проблему –

ответ

0

Вы можете прочитать свою строку как поток символов и записать начальную и конечную позицию каждого токена, который вы хотите разбор.

Это все еще создает объект для каждого токена, но если ваши жетоны относительно длинные, то два поля int, которые будут содержать ваши объекты, намного меньше, чем соответствующая строка.

Но прежде чем отправиться в путешествие, вы должны просто убедиться, что вы не держите свои обрезанные струны больше времени, чем нужно.

0

Предполагая, что вы есть String содержащий <string1>, <string2>, и вы просто хотите, чтобы разделить его без возможно обрезки частей:

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

(Обратите внимание, что это в основном, как String.trim() реализуется, только с start и end вместо 0 и length)

Тогда зови, как:

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

Я хочу обрезать части, то есть отдельные строки. –

+0

Зачем мне когда-либо использовать эту отделку вместо стандартной? Цель заключалась в том, чтобы избежать потери памяти, но вы используете ту же дополнительную память (= вы возвращаете новую строку) как встроенный 'trim()' – tucuxi

+0

Потому что 'String.trim()' только выравнивает с начала и конца Струна. Чтобы использовать это, вы должны разбить строку (создает массив и две строки), а затем обрезать их (до двух строк). Этот подход создает ровно две строки, а не 4 строки и массив. –

-1

Я думаю, что вы можете напрямую записывать данные результата в новый файл.

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

, если вы используете модель m-thread, вы можете отделить свой файл, позволить им быть немного chunk-файла для логического, а затем вышеописанный метод также хорошо работает. – Axl

+0

Написание одного символа за один раз займет навсегда. Вам нужно его буферизировать. – markbernard

2

Я был бы удивлен, если неустойчивый класс String вызывает проблемы; JVM очень эффективен и является результатом многолетней инженерной работы.

При этом Java предоставляет изменяемый класс для управления строками, называемыми StringBuilder. Вы можете прочитать документы here.

Если вы работаете над нитками, consider using StringBuffer.

0

Как вы уже заметили, строки неизменяемы. Поэтому решение состоит в том, чтобы не использовать String, а скорее нечто изменяемое. StringBuffer - подходящий класс.

Однако StringBuffer не включает в себя декоративную метод, так что вы можете использовать что-то вроде:

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

Если вы хотите, чтобы избежать String тогда вы должны справиться с этим самостоятельно, используя char и StringBuilder, как это:

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

Мы можем обращаться с помощью Regex.

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