Анализ текстовых файлов в Java

Я читаю текстовый файл, используя FileInputStream, который помещает содержимое файла в массив байтов. Затем я преобразую массив байтов в строку, используя новую строку (байт).

Как только у меня есть строка, я использую String.split("\n"), чтобы разбить файл на массив String, а затем взять этот массив строк и проанализировать его, выполнив String.split(",") и удерживая содержимое в Arraylist.

У меня есть файл 200 Мбайт +, и у него заканчивается память, когда я запускаю JVM с 1 ГБ памяти. Я знаю, что я должен что-то делать правильно, я просто не уверен, что метод, который я обрабатываю, неверен или структуру данных, которую я использую.

Также мне нужно около 12 секунд, чтобы проанализировать файл, который кажется очень большим. Может ли кто-нибудь указать, что я могу делать, из-за чего у меня заканчивается память и что может заставлять мою программу работать медленнее?

Содержимое файла выглядит следующим образом:

"12334", "100", "1.233", "TEST", "TEXT", "1234"
"12334", "100", "1.233", "TEST", "TEXT", "1234"
.
.
.
"12334", "100", "1.233", "TEST", "TEXT", "1234"

Спасибо

Ответ 1

Похоже, вы делаете что-то не так со мной - происходит создание целого lotta-объекта.

Насколько представительным является этот "тестовый" файл? Что вы действительно делаете с этими данными? Если это типично для того, что у вас действительно есть, я бы сказал, что в этих данных много повторений.

Если все равно будет в Strings, начните с BufferedReader, чтобы читать каждую строку. Предварительно выделите этот список размером, близким к тому, что вам нужно, чтобы вы не тратили ресурсы, добавляя к нему каждый раз. Разделить каждую из этих строк в запятой; обязательно удалите двойные кавычки.

Вы можете спросить себя: "Зачем мне весь этот файл в памяти сразу?" Можете ли вы немного почитать, немного обработать и не иметь сразу все в памяти? Только вы хорошо знаете свою проблему, чтобы ответить.

Возможно, вы можете запустить jvisualvm, если у вас есть JDK 6 и посмотреть, что происходит с памятью. Это будет отличным ключом.

Ответ 2

Я не уверен, насколько эффективна память, но мой первый подход будет использовать Scanner, поскольку это невероятно простой в использовании:

File file = new File("/path/to/my/file.txt");
Scanner input = new Scanner(file);

while(input.hasNext()) {
    String nextToken = input.next();
    //or to process line by line
    String nextLine = input.nextLine();
}

input.close();

Проверьте API на то, как изменить разделитель, используемый для разделения токенов.

Ответ 4

Похоже, что у вас в настоящее время есть 3 копии всего файла в памяти: массив байтов, строка и массив строк.

Вместо того, чтобы читать байты в массив байтов, а затем преобразовывать их в символы с помощью new String(), было бы лучше использовать InputStreamReader, который будет преобразовываться в символы пошагово, а не во всех фронтах.

Кроме того, вместо того, чтобы использовать String.split( "\n" ) для получения отдельных строк, вы должны читать по одной строке за раз. Вы можете использовать метод readLine() в BufferedReader.

Попробуйте что-то вроде этого:

BufferedReader reader = new BufferedReader(new InputStreamReader(fileInputStream, "UTF-8"));
try {
  while (true) {
    String line = reader.readLine();
    if (line == null) break;
    String[] fields = line.split(",");
    // process fields here
  }
} finally {
  reader.close();
}

Ответ 5

Если у вас есть 200 000 000 файлов символов и разбивается на каждые пять символов, у вас есть 40 000 000 String объектов. Предположим, что они используют данные фактического символа с оригинальным 400 МБ String (char - 2 байта). A String скажем 32 байта, так что это 1,280,000,000 байт объектов String.

(Вероятно, стоит отметить, что это очень зависит от реализации. split может создавать целые строки с полностью новой поддержкой char[] или OTOH, совместно использовать некоторые общие значения String. Некоторые реализации Java не используют срез char[]. Некоторые могут использовать компактную форму, подобную UTF-8, и дают очень плохое время произвольного доступа.)

Даже если предположить более длинные строки, это много объектов. С таким большим количеством данных вы, вероятно, захотите работать с большинством из них в компактной форме, такой как оригинал (только с индексами). Только конвертировать в объекты, которые вам нужны. Реализация должна быть подобна базе данных (хотя они традиционно не обрабатывают строки переменной длины эффективно).

Ответ 6

При вызове/вызове вашей программы вы можете использовать эту команду: java [-options] className [args...]
вместо [-options] обеспечивают больше памяти, например, -Xmx1024m или больше. но это всего лишь обходной путь, и вам нужно изменить механизм анализа ur.