Как написать 1000 записей на файл или подождать, чтобы иметь больше записей, чтобы записать, а затем разбить файл? - PullRequest
0 голосов
/ 05 июня 2019

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

  • Назовите файл в следующей структуре (FileCounter)_(StartID)_(EndID)
  • Максимум 1000 записей на файл
  • Если не хватает 1000 записей для записи, подождите не более 10 секунд, если они были добавлены, запишите все это в файл, в противном случае запишите оставшийся список в файл (не достаточно 1000), если после ожидания ничего не записать, создайте пустой файл с именем (FileCounter)_0_0

Мой подход заключается в использовании 2 потоков, 1 потока для генерации данных, затем передачи их в очередь, 1 потока для извлечения из очереди, добавления в список и записи списка в файл.

//Generate function
public void generatedata() {
int capacity = 1678;
synchronized(users) {
for(int index = 0; index <capacity; index++) {          
users.add(generateUser());
// notify to read thread
users.notifyAll();
}
} 
//Write function
public void writeToFile(ArrayList<User> u) {
String fileName  ="";
if(!u.isEmpty()) {
String filename = "" + (++FileCounter) + "_"+ u.get(0).getId() + "_" + 
u.get(u.size() - 1).getId() + ".txt";
try {
    FileWriter writer = new FileWriter(filename, true);
for (User x : u) {
System.out.println(x.toString());
    writer.write(x.getId() + " | " + x.getFormatedDate() + " | " + 
x.getSex()  + " | " + x.getPhoneNum().getPhoneNumber() + " | " + 
x.getPhoneNum().getProvider() + "\r\n");
}
writer.close();
}
catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} 
}
else {
    try {
        fileName = ""+(++FileCounter) +"_0_0.txt";
        File f = new File(fileName);
        f.createNewFile();
    } catch (IOException ex) {
        Logger.getLogger(UsersManager.class.getName()).log(Level.SEVERE, 
null, ex);
    }
}
}
//Read function
    public ArrayList<User> ReadFromQueue(ArrayList<User> u) {
    while(true) {
    try {

    int size = users.size();
    if(users.isEmpty() && u.size() < 1000) {
        users.wait(10000);

        if(isChanged(size)) {
            System.out.println("Size changed here");
            u.add(users.take());
        }
        else return u;
    }
    if(u.size() == 1000)  {
        System.out.println("Check the size is 1000");
        return u;
    }
     u.add(users.take());
    } catch (InterruptedException ex) {
    Logger.getLogger(UsersManager.class.getName()).log(Level.SEVERE, 
    null, ex);
    }
    }

Работает нормально, когда я запускаю 1 поток для генерации данных, 1 поток для чтения и записи данных в файл, но когда я использую поток 2 ++ для каждого потока генерации потока записи, возникает 1 проблема:

  1. Список, записанный в файле, по-прежнему содержит 1000 записей, как и ожидалось, но не является последовательным, он только в порядке возрастания.

Мой вывод выглядит так:

1_2_1999.txt
2_1_2000.txt
3_2001_3000.txt

Мой ожидаемый результат:

1_1_1000.txt
2_1001_2000.txt
....

Заранее спасибо!

Ответы [ 3 ]

0 голосов
/ 06 июня 2019

У меня был проект, в котором мне нужно было создать 90-секундные превью из больших файлов MP4. Я сделал так, чтобы несколько потоков запускались с доступом к общей очереди имен файлов. Каждый поток потребляет работу из очереди с помощью queue.poll ().

Вот конструктор:

public Worker(Queue<String> queue, String conferenceYear, CountDownLatch startSignal, CountDownLatch doneSignal) {
        this.queue = queue;
        this.startSignal = startSignal;
        this.doneSignal = doneSignal;
    }

Затем, как я уже сказал выше, я продолжаю опрашивать данные:

public void run() {
    while (!queue.isEmpty()) {

                String fileName = queue.poll() + ".mp4";

                File f = new File("/home/ubuntu/preview_" + fileName);
                if (fileName != null && !f.exists()) {
                    System.out.println("Processing File " + fileName + "....");

Я запустил эти темы в другом классе под названием WorkLoad:

public static void main(String[] args) {
        long startTime = System.currentTimeMillis();

        BlockingQueue<String> filesToDownload = new LinkedBlockingDeque<String>(1024);
        BlockingQueue<String> filesToPreview = new LinkedBlockingDeque<String>(1024);
        BlockingQueue<String> filesToUpload = new LinkedBlockingDeque<String>(1024);

for (int x = 0; x < NUMBER_OF_THREADS; x++) {
                workers[x] = new Thread(new Worker(filesToPreview, currentYear, startSignal, doneSignal));
                workers[x].start();
            }

В вашем конкретном случае вы можете предоставить каждому потоку свое собственное имя файла или дескриптор файла. Если вы хотите, чтобы имена файлов и записи располагались в хронологическом порядке, просто запустите 2 потока, 1 для сбора данных и помещения в очередь, с барьером / лимитом в 1000 записей, а другой поток в качестве потребителя.

0 голосов
/ 07 июня 2019

исходный код создает несколько потоков. Я могу создать 90-секундные фрагменты из более чем 1000 видео MP4 за 30 минут.

Здесь я создаю поток для каждого процессора, в моем экземпляре AWS EC2 обычно получается как минимум 4 потока:

/**
         * Here we can find out how many cores we have.
         * Then make the number of threads NUMBER_OF_THREADS = the number of cores.
         */
        NUMBER_OF_THREADS = Runtime.getRuntime().availableProcessors();
        System.out.println("Thread Count: "+NUMBER_OF_THREADS);

for (int x = 0; x < NUMBER_OF_THREADS; x++) {
            workers[x] = new Thread(new MyClass(param1, param2));
            workers[x].start();
        }
0 голосов
/ 06 июня 2019

с использованием потокового подхода лучше всего подходит, когда вы не хотите контролировать количество на файл.но поскольку у вас есть ограничение в 1000 записей, возможно, проще использовать счетчик;

 public class DataReaderWriter(){

//keeps track of where you left off at, which row in source data.        
static int currentRowInSourceData = 0;

        public static void main(String[] args){

        List<ContactRecord> contacts = getMoreData();
        writeRecords(contacts);
    }



    writeRecords(List<ContactRecord> contacts){

    int maxRecords = currentRowInSourceData+1000;
    for(int i = currentRowInSourceData;i<maxRecords;i++){
        ContactRecord c = contacts.get(i);
        writeToFile(c);
        currentRowInSourceData++;

    }

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