Считывание из файла и запись в другой файл в потоке

 
 
 
Сообщения:103
Добрый день. Есть такой класс, который считывает строки из одного файла и записывает в другой. Как сделать так, чтобы данные из файла считывались в одном потоке, а в другой файл записывались в другом потоке?

public class Test{
    private String separator = File.separator;
    private String path = "C:" + separator + "files" + separator;

    public void method(String filename, String newFileName) throws IOException {
        BufferedReader buf = new BufferedReader(new InputStreamReader(new FileInputStream(path + filename)));
        PrintWriter write = new PrintWriter(new FileWriter(path + newFileName), true);
        String tmp;
        while ((tmp = buf.readLine()) != null) {
            try {
                write.println(tmp);
            } catch (Exception e) {

            }
        }
    }
}
 
 
Сообщения:103
Имеется ввиду создать два собственных потока. В одном чтобы было это BufferedReader buf = new BufferedReader(new InputStreamReader(new FileInputStream(path + filename)));
а в другом чтобы уже происходила запись в файл так PrintWriter write = new PrintWriter(new FileWriter(path + newFileName), true);
 
 
Сообщения:1402
Создаете класс например Buffer, в нем синхронизированная Queue и 2 метода add - добавляет строку в конец очереди и get берет строку из начал очереди.
Первый тред просто читает файл и вызывает add для каждой строки
Второй тред вызывает get и пишет полученные данные в файл. Если get вернул null можете делать sleep на 1 секунду, либо в самом методе get сделать синхронизацию с wait, а при add делать notify, если очередь была пуста
 
 
Сообщения:103
Пробую так:

public class Buffer {
    private Queue<String> queue = new SynchronousQueue<>();
    private String separator = File.separator;
    private String path = "C:" + separator + "files" + separator;

    public void addQueue(String file) throws IOException {
        BufferedReader buff = new BufferedReader(new InputStreamReader(new FileInputStream(path + file)));
        String tmp;
        while ((tmp = buff.readLine()) != null) {
            queue.add(tmp);
        }
    }

    public void getQueue(String file) throws IOException {
        PrintWriter writer = new PrintWriter(new FileWriter(path + file));
        writer.println(queue.element());
    }
}

class Test {
    public static void main(String[] args) throws IOException {
        String inFile = "f1.txt";
        String outFile = "f2.txt";

        Buffer buffer = new Buffer();
        buffer.addQueue(inFile);
        buffer.getQueue(outFile);
    }
}


Выдается ошибка:

Exception in thread "main" java.lang.IllegalStateException: Queue full
	at java.util.AbstractQueue.add(AbstractQueue.java:98)
	at filesreader.Buffer.addQueue(Buffer.java:19)
	at filesreader.Test.main(Buffer.java:35)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)


Что в моем коде не так, и как реализовать первый и второй поток можете чуть подробнее объяснить?
Изменен:15 ноя 2016 12:21
 
 
Сообщения:1402
У вас какая-то экзотическая очередь используйте
ConcurrentLinkedQueue
методы должны быть
void add(String line);
String get();

Первый поток использует метод add, второй get
Первый поток читает данные и отдает add
Второй забирает с помощью get и записывает их
 
 
Сообщения:103
Вот что получилось

package filesreader;

import java.io.*;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

public class Buffer {
    private static ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();

    public void addQueue(String line){
        queue.add(line);
    }

    public String getQueue(){
        return queue.poll();
    }
}

class Reader implements Runnable {
    Buffer buffer = new Buffer();
    private String separator = File.separator;
    private String path = "C:" + separator + "files" + separator;
    private String file;

    public Reader(Buffer buffer, String file) {
        this.buffer = buffer;
        this.file = file;
    }

    @Override
    public void run() {
        try {
            BufferedReader b = new BufferedReader(new InputStreamReader(new FileInputStream(path + file)));
            String tmp;
            while ((tmp = b.readLine()) != null) {
                buffer.addQueue(tmp);
            }
        } catch (IOException ex) {

        }
    }
}

class Writer implements Runnable {
    Buffer buffer = new Buffer();
    private String separator = File.separator;
    private String path = "C:" + separator + "files" + separator;
    private String file;

    public Writer(Buffer buffer, String file) {
        this.buffer = buffer;
        this.file = file;
    }

    @Override
    public void run() {
        try {
            PrintWriter writer = new PrintWriter(new FileWriter(path + file));
            writer.println(buffer.getQueue());
        } catch (IOException ex) {

        }
    }
}

class Test {
    public static void main(String[] args) throws IOException {
        String inFile = "f1.txt";
        String outFile = "f2.txt";

        Buffer buffer = new Buffer();

        Reader reader = new Reader(buffer, inFile);
        Writer writer = new Writer(buffer, outFile);

        Thread p1 = new Thread(reader);
        Thread p2 = new Thread(writer);

        p1.start();
        p2.start();
    }
}


ошибок нет, но в файл f2.txt ничего не записывает
Изменен:15 ноя 2016 13:05
 
 
Сообщения:1402
У вас main завершает работу и потоки p1 и p2 умирают, сделайте в конце метода sleep(10000)
 
 
Сообщения:103
У меня в цикле while из класса Reader строки заносятся в очередь, но после цикла когда вывожу содержимое очереди, она оказывается пустой. Почему так?
 
 
Сообщения:1402
У вас буффер должен быть общим, а не иметь 2 отдельных инстанса
Изменен:15 ноя 2016 20:05
 
 
Сообщения:103
Как это сделать? Я не очень понимаю пока что о чем речь.
 
 
Сообщения:1402
А нет, static queue хоть и портит код, но не может повлиять на код. У вас тред который считывает забирает первую строку слишком быстро, до того как туда положат данные. К тому же делает это 1 раз, а не в цикле, да ещё вы поток не закрываете.
Ради эксперимента попробуйте перед buffer.getQueue() поставить sleep(3000)
Buffer buffer = new Buffer();
заменить на
Buffer buffer ; в потоках, статик очередь сделать не статической
Добавление в очередь нормальное, но я бы добавил логгирование на всякий случай
чтение из очереди и запись в файле тоже должно быт в цикле и продумайте, когда надо перестать читать данные из очереди
и закрывайте файловые дескрипторы
 
 
Сообщения:103
Буду разбираться сейчас.
 
 
Сообщения:103
Получилось. Вот мой код.

package filesthread;

import java.io.*;
import java.util.concurrent.ConcurrentLinkedQueue;

public class Buffer {
    private ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();

    public void add(String str) {
        queue.offer(str);
    }

    public String get() {
        return queue.poll();
    }

    public int getSize() {
        return queue.size();
    }
}

class Reader implements Runnable {
    Buffer buffer;
    private String separator = File.separator;
    private String path = "C:" + separator + "files" + separator;
    private String file;

    public Reader(Buffer buffer, String file) {
        this.buffer = buffer;
        this.file = file;
    }

    @Override
    public void run() {
        try (BufferedReader buf = new BufferedReader(new InputStreamReader(new FileInputStream(path + file)))) {
            String tmpStr;
            while ((tmpStr = buf.readLine()) != null) {
                buffer.add(tmpStr);
            }
        } catch (IOException ex) {

        }
    }
}

class Writer implements Runnable {
    Buffer buffer;
    private String separator = File.separator;
    private String path = "C:" + separator + "files" + separator;
    private String file;

    public Writer(Buffer buffer, String file) {
        this.buffer = buffer;
        this.file = file;
    }

    @Override
    public void run() {
        try (PrintWriter writer = new PrintWriter(new FileWriter(path + file))) {
            do {
                Thread.sleep(1000);
                writer.println(buffer.get());
            } while (buffer.getSize() != 0);
        } catch (IOException | InterruptedException ex) {

        }
    }
}

class Test {
    public static void main(String[] args) {
        String inFile = "f1.txt";
        String outFile = "f2.txt";

        Buffer buffer = new Buffer();

        Reader reader = new Reader(buffer, inFile);
        Writer writer = new Writer(buffer, outFile);

        Thread p1 = new Thread(reader);
        Thread p2 = new Thread(writer);

        p1.start();
        p2.start();

        try {
            p1.join();
            p2.join();
        } catch (InterruptedException ex) {

        }
    }
}


Только можно спросить некоторые вещи:
1. Какая разница если указать Buffer buffer; или Buffer buffer = new Buffer (); оба варианта работают в этом коде. Как правильнее указать и почему?

2. Почему static у queue портит код Вы сказали? Тоже хотел бы понять как правильнее писать и почему?

3. Как теперь мне переделать код, чтобы не было sleep (), а потоки взаимодействовали через wait и notify? Например считали из файла одну строку и добавили в очередь уведомили второй поток что он может из очереди взять строку и записать в новый файл. И т.д.
 
 
Сообщения:103
Не судите строго за возможно глупые вопросы, я только учусь)
 
 
Сообщения:1402
Quote:
Buffer buffer = new Buffer();

Создается мусорный объект который не используется

Quote:
. Почему static у queue портит код Вы сказали?

Потому что это неправильно, создается 1 очередь на все объекты

Quote:
. Как теперь мне переделать код, чтобы не было sleep (), а потоки взаимодействовали через wait и notify? Например считали из файла одну строку и добавили в очередь уведомили второй поток что он может из очереди взять строку и записать в новый файл. И т.д.

после того как положили в очередь вызываете метод в котором делаете notify на какой-нибудь объект
если берете из очереди и получаете null, то вызываете метод в котором делаете wait на данный объект
 
Модераторы:Нет
Сейчас эту тему просматривают:Нет