Чтение огромных файлов (больше 2Гб)

Рейтинг: 2Ответов: 1Опубликовано: 07.04.2015

Столкнулся с проблемой считывания динамического файла, в который каждую секунду пишется по 50-75 строк. За сутки набегает овер 500 мб инфы. Это все текст. Задача как можно быстрее считывать инфу, сравнить строку с эталонной, и если такая найдена, то создать новый файл и написать его время нахождения.

Загвоздка в том, что с динамическими файлами не работал. Был бы рад примеру с разбивкой файла на 2 (или другое кол-во) части и прочитывать каждой части отдельным потоком.

Вот что получилось:

public class ReadFile1 {
    static File file = null;
    static File fileJCO = new File("JCO.log");
    static String path = "C:\\Documents and Settings\\user\\Рабочий стол\\ReadFile1\\test.log";
    static String line;
    static FileReader fileReader = null;
    //static BufferedReader bufferedReader = null;
    static ArrayList<String> words = new ArrayList<String>();
    static String lineLC = null;
    static String wordLC = null;
    static int currentLine = 0;
    static int beginI = 0;
    static int endI = 0;
    static int wordPosition = 0;


    public static void main(String[] args) throws IOException {
        try {
            file = new File(path);
            fileReader = new FileReader(file);
        } catch (FileNotFoundException fne) {
            System.out.println(path);
        }
        BufferedReader bufferedReader = new BufferedReader(fileReader);
        BufferedWriter outputJCO = new BufferedWriter(new FileWriter(fileJCO));
        words.add("TIME        ");
        try {
            while ((line = bufferedReader.readLine()) != null) {
                lineLC = line.toLowerCase();
                currentLine++;
                for (String word : words) {
                    wordLC = word.toLowerCase();
                    if (lineLC.contains(wordLC)) {
                        wordPosition = lineLC.lastIndexOf(wordLC);
                        beginI = wordPosition;
                        if (beginI < 10) {
                            beginI = 0;
                        } else {
                            beginI -= 10;
                        }
                        endI = wordPosition;
                        if (endI > (lineLC.length() - wordLC.length() - 10)) {
                            endI = lineLC.length();
                        } else {
                            endI += wordLC.length() + 20;
                        }
                        System.out.println(line.substring(beginI, wordPosition) + word.toUpperCase() +
                                line.substring(wordPosition + wordLC.length(), endI));
                        outputJCO.write(" Ошибка JCO_ERROR_COMMUNICATION: обнаружена в " +
                                line.substring(beginI, wordPosition) + word.toUpperCase() +
                                line.substring(wordPosition + wordLC.length(), endI) + " по серверному времени" + "\n");
                    }
                }
            }
            fileReader.close();
            bufferedReader.close();
            outputJCO.close();
        }catch (IOException ioe){
            System.out.println(ioe.toString());
        }
    }
}

Строчки которые интересуют:

Caused by: com.sap.conn.jco.JCoException: (102) JCO_ERROR_COMMUNICATION: Connect to SAP gateway failed
Connection parameters: TYPE=A DEST=10.35.94.18.976253 ASHOST=10.35.94.18 SYSNR=00 GWHOST=10.35.94.18 GWSERV=sapgw00 PCS=1 COMM_CP=15 LOCATION CPIC (TCP/IP) on local host with Unicode
ERROR partner '10.35.94.18:sapgw00' not reached
TIME Tue Nov 18 09:09:14 2014
RELEASE 720
COMPONENT NI (network interface)
VERSION 40
RC -10
MODULE ./nibuf.cpp
LINE 4634
DETAIL NiBufIConnect: connection pending after 60000ms

В конечном итоге, потенциал приложения по просчитыванию (замерял у себя на сервере): 130000 строк в секунду. Проглотил файл в 5,33Гб. Прочитывает лог находит фразу и со смещением от найденной фразы выводит в другой файл.

Как можно улучшить этот код?

Ответы

▲ 6Принят

Непонятно, в чем именно у вас проблема. Давайте по пунктам:

1) Потоки вам точно не помогут, так как (вам правильно заметили в комментарии) узким местом будет ввод/вывод, а не CPU, и вы только замедлите работу.

2) Если задача состоит в том, что вам нужно при каждом запуске программы разбирать заново весь файл, который очень велик, поэтому скорость важна, то вам следует почитать вот это: http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quickly

3) Если же (мне кажется, что это ваш случай) задача состоит в том, что ваша программа должна висеть и постоянно считывать новые данные, приходящие в файл, и обрабатывать их, то все очень просто: читаем построчно и обрабатываем прочитанные данные; если же файл закончился, ненадолго засыпаем (чтобы не загружать процессор), а потом пробуем прочитать новые данные, вдруг они пришли, и так по-кругу. 50-75 строк в секунду -- это совсем немного, никаких особых ухищрений не нужно. Получится что-то вроде:

...
String line;

while (true) {
    while ((line = in.readLine()) != null) {
        // Обработка строки
        ...
    }
    // Вышли из цикла, значит данные в файле пока закончились.
    // Засыпаем на секунду, а затем пробуем снова.
    Thread.sleep(1000);
}
...