Java: приостановить поток и получить позицию в файле - PullRequest
0 голосов
/ 22 апреля 2011

Я пишу приложение на Java с многопоточностью, которое я хочу приостановить и возобновить.
Поток читает файл построчно, находя совпадающие строки с шаблоном.Это должно продолжаться на том месте, где я остановил поток.Для чтения файла я использую BufferedReader в сочетании с InputStreamReader и FileInputStream.

fip = new FileInputStream(new File(*file*));
fileBuffer = new BufferedReader(new InputStreamReader(fip));

Я использую этот FileInputStream, потому что мне нужен указатель файла для позиции в файле.
При обработке строк, которые он пишетсоответствующие строки в базе данных MySQL.Чтобы использовать MySQL-соединение между потоками, я использую ConnectionPool, чтобы убедиться, что только один поток использует одно соединение.

Проблема в том, что когда я приостанавливаю потоки и возобновляю их, несколько совпадающих строк просто исчезают.Я также попытался вычесть размер буфера из смещения, но он все еще имеет ту же проблему.

Как найти достойный способ решить эту проблему или что я делаю не так?

Некоторые дополнительные сведения:

Цикл

    // Regex engine
    RunAutomaton ra = new RunAutomaton(this.conf.getAuto(), true);
    lw = new LogWriter();

        while((line=fileBuffer.readLine()) != null) {
            if(line.length()>0) {
                if(ra.run(line)) {
                        // Write to LogWriter
                        lw.write(line, this.file.getName());
                        lw.execute();
                    }
                }
            }
            // Loop when paused.
            while(pause) { }
        }

Расчетпоместить в файл

// Get the position in the file
public long getFilePosition() throws IOException {
    long position = fip.getChannel().position() - bufferSize + fileBuffer.getNextChar();
    return position;
}

положить его в базу данных

            // Get the connector
            ConnectionPoolManager cpl = ConnectionPoolManager.getManager();
            Connector con = null;
            while(con == null)
                con = cpl.getConnectionFromPool();
            // Insert the query
            con.executeUpdate(this.sql.toString());
            cpl.returnConnectionToPool(con);

Ответы [ 3 ]

2 голосов
/ 22 апреля 2011

Вот пример того, что, я полагаю, вы ищете. Вы не продемонстрировали большую часть своей реализации, поэтому трудно отладить то, что может привести к пробелам для вас. Обратите внимание, что позиция FileInputStream будет кратна 8192, потому что BufferedReader использует буфер этого размера. Если вы хотите использовать несколько потоков для чтения одного и того же файла, вы можете найти этот ответ полезным.

public class ReaderThread extends Thread {
    private final FileInputStream fip;
    private final BufferedReader fileBuffer;
    private volatile boolean paused;

    public ReaderThread(File file) throws FileNotFoundException {
        fip = new FileInputStream(file);
        fileBuffer = new BufferedReader(new InputStreamReader(fip));
    }

    public void setPaused(boolean paused) {
        this.paused = paused;
    }

    public long getFilePos() throws IOException {
        return fip.getChannel().position();
    }

    public void run() {
        try {
            String line;
            while ((line = fileBuffer.readLine()) != null) {
                // process your line here
                System.out.println(line);

                while (paused) {
                    sleep(10);
                }
            }
        } catch (IOException e) {
            // handle I/O errors
        } catch (InterruptedException e) {
            // handle interrupt
        }
    }
}
1 голос
/ 22 апреля 2011

Я думаю, корень проблемы в том, что вы не должны вычитать bufferSize.Скорее вы должны вычитать количество непрочитанных символов в буфере.И я не думаю, что есть способ получить это.

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

FileReader 
< BufferedReader 
< custom filter reader
< BufferedReader(sz == 1)

Конечный BufferedReader существует для того, чтобы вы могли использовать readLine ..., но вам нужно установить размер буфера в 1, чтобы количество символов из вашего фильтрасоответствует позиции, которой достигло приложение.

В качестве альтернативы, вы можете реализовать свой собственный метод readLine() в программе чтения пользовательских фильтров.

0 голосов
/ 05 мая 2011

После нескольких дней поиска я обнаружил, что действительно вычитание размера буфера и добавление позиции в буфере было неправильным способом сделать это. Позиция никогда не была правильной, и я всегда пропускал некоторые строки.
При поиске нового способа выполнения своей работы я не учитывал количество символов, потому что это слишком много символов для подсчета, что сильно снизит мою производительность. Но я нашел кое-что еще. Инженер-программист Марк С. Колич создал класс JumpToLine , который использует библиотеку Apache IO для перехода к заданной строке. Он также может предоставить последнюю прочитанную строку, так что это действительно то, что мне нужно.
На его домашней странице есть несколько примеров для интересующихся.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...