Анализ текстовых файлов в 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 на то, как изменить разделитель, используемый для разделения токенов.
Ответ 3
Взгляните на эти страницы. Они содержат множество парсеров с открытым исходным кодом CSV. JSaPar является одним из них.
Ответ 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.