2015-05-25 3 views
1

Я пытаюсь как можно быстрее прочитать большой текстовый файл.Чтение большого текстового файла быстрее

  • Линии, начинающиеся с '!' передаются.
  • Линии с 8 CSV имеют последнее значение.
  • В значении никогда не будет значения «(не нужно использовать opencsv).
  • Все добавлено к длинной строке, декодированной позже.

Так что это мой код

BufferedReader br = new BufferedReader(new FileReader("C:\\Users\\Documents\\ais_messages1.3.txt")); 
String line, aisLines="", cvsSplitBy = ","; 
try { 
    while ((line = br.readLine()) != null) { 
     if(line.charAt(0) == '!') { 
     String[] cols = line.split(cvsSplitBy); 
     if(cols.length>=8) { 
      line = ""; 
      for(int i=0; i<cols.length-1; i++) { 
       if(i == cols.length-2) { 
        line = line + cols[i]; 
       } else { 
        line = line + cols[i] + ","; 
       } 
      } 
      aisLines += line + "\n"; 
     } else { 
      aisLines += line + "\n"; 
     } 
     } 
    } 
} catch (IOException e) { 
    e.printStackTrace(); 
} 

Так что сейчас он читает 36890 строк в 14 секунд. Я также попробовал InputStreamReader:

InputStreamReader isr = new InputStreamReader(new FileInputStream("C:\\Users\\Documents\\ais_messages1.3.txt")); 
    BufferedReader br = new BufferedReader(isr); 

и потребовалось столько же времени. Есть ли более быстрый способ чтения большого текстового файла (100 000 или 1 000 000 строк)?

+2

используйте 'StringBuilder' для конкатенации строк – tony200910041

+0

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

+0

Что должно произойти, если имеется более 8 значений? В этом случае ваш код всегда удаляет последний элемент. Неужели это так должно быть? – SpiderPig

ответ

3

Прекратите пытаться создать aisLines как большую строку. Используйте ArrayList<String>, к которому вы добавляете строки. Это занимает 0,6% времени, как ваш метод на моей машине. (Этот код обрабатывает 1 000 000 простых строк за 0,75 секунды.) И это уменьшит усилия, необходимые для обработки данных позже, поскольку они уже будут разделены линиями.

BufferedReader br = new BufferedReader(new FileReader("data.txt")); 
List<String> aisLines = new ArrayList<String>(); 
String line, cvsSplitBy = ","; 
try { 
    while ((line = br.readLine()) != null) { 
     if(line.charAt(0) == '!') { 
      String[] cols = line.split(cvsSplitBy); 
      if(cols.length>=8) { 
       line = ""; 
       for(int i=0; i<cols.length-1; i++) { 
        if(i == cols.length-2) { 
         line = line + cols[i]; 
        } else { 
         line = line + cols[i] + ","; 
        } 
       } 
       aisLines.add(line); 
      } else { 
       aisLines.add(line); 
      } 
     } 
    } 
} catch (Exception e) { 
    e.printStackTrace(); 
} 

Если вы действительно хотите большой String в конце (потому что вы взаимодействия с чужой код, или любой другой), он все равно будет быстрее конвертировать ArrayList обратно в одну строку, чем делайте то, что делаете.

+0

кажется, что расщепление и повторное объединение - это чрезмерная работа? Возможно, 'if (StringUtils.countMatches (строка,", ")> = 7)' и 'String shortenLine = line.substring (0, line.lastIndexOf (", "));' будет работать лучше? –

+0

Удивительно, да, декодеру требуется гигантская строка, расщепленная с помощью регулярного выражения =, но плохо помещала все в arraylist, а затем превращала arrlist в гигантскую строку после чтения файла. –

0

Вы можете использовать один поток, который читает ваш большой файл csv, и несколько потоков обрабатывают все строки. То, как я делаю, это использовать шаблон Producer-Consumer и BlockingQueue.

Производитель

Создание одного Producer тему, которая отвечает только для чтения строки файла CSV, и хранит строки в BlockingQueue. Сторона производителя ничего не делает.

Потребители

Создание нескольких потребительских Тем, проходят один и тот же объект BlockingQueue в ваших потребителей. Выполнение занимает много времени в вашем классе Consumer Thread.

Следующий код дает вам представление о решении проблемы, а не о решении. Я был реализован с помощью python, и он работает намного быстрее, чем использование одного потока. Язык не java, но теория позади одна и та же.

import multiprocessing 
import Queue 

QUEUE_SIZE = 2000 


def produce(file_queue, row_queue,): 

    while not file_queue.empty(): 
     src_file = file_queue.get() 
     zip_reader = gzip.open(src_file, 'rb') 

     try: 
      csv_reader = csv.reader(zip_reader, delimiter=SDP_DELIMITER) 

      for row in csv_reader: 
       new_row = process_sdp_row(row) 
       if new_row: 
        row_queue.put(new_row) 
     finally: 
      zip_reader.close() 


def consume(row_queue): 
    '''processes all rows, once queue is empty, break the infinit loop''' 
    while True: 
     try: 
      # takes a row from queue and process it 
      pass 
     except multiprocessing.TimeoutError as toe: 
      print "timeout, all rows have been processed, quit." 
      break 
     except Queue.Empty: 
      print "all rows have been processed, quit." 
      break 
     except Exception as e: 
      print "critical error" 
      print e 
      break 


def main(args): 

    file_queue = multiprocessing.Queue() 
    row_queue = multiprocessing.Queue(QUEUE_SIZE) 

    file_queue.put(file1) 
    file_queue.put(file2) 
    file_queue.put(file3) 

    # starts 3 producers 
    for i in xrange(4): 
     producer = multiprocessing.Process(target=produce,args=(file_queue,row_queue)) 
     producer.start() 

    # starts 1 consumer 
    consumer = multiprocessing.Process(target=consume,args=(row_queue,)) 
    consumer.start() 

    # blocks main thread until consumer process finished 
    consumer.join() 

    # prints statistics results after consumer is done 

    sys.exit(0) 


if __name__ == "__main__": 
    main(sys.argv[1:]) 
+0

У меня мало опыта с многопоточными записями, но я буду читать больше :) Спасибо за помощь. –

1

В большинстве операций потребляющего является IO наиболее эффективным способом является разделение потоков для разбора и чтения:

private static void readFast(String filePath) throws IOException, InterruptedException { 
    ExecutorService executor = Executors.newWorkStealingPool(); 
    BufferedReader br = new BufferedReader(new FileReader(filePath)); 
    List<String> parsed = Collections.synchronizedList(new ArrayList<>()); 
    try { 
     String line; 
     while ((line = br.readLine()) != null) { 
      final String l = line; 
      executor.submit(() -> { 
       if (l.charAt(0) == '!') { 
        parsed.add(parse(l)); 
       } 
      }); 
     } 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    executor.shutdown(); 
    executor.awaitTermination(1000, TimeUnit.MINUTES); 


    String result = parsed.stream().collect(Collectors.joining("\n")); 
} 

Для моего компьютера он взял 386ms против 10787ms с медленной

+0

Я пытаюсь решить это решение, столкнувшись с проблемами (parse (l)); (метод не найден) –

Смежные вопросы