2016-12-22 21 views
1

У меня есть требование прочитать Огромный Плоский файл, без сохранения всего файла в памяти. Это плоский файл с несколькими сегментами, каждая запись начинается с записи заголовка, обозначенной «H» в начале, за которой следуют многие строки, а затем снова записи заголовка, этот шаблон повторяется .Чтение огромного файла с фиксированной шириной

HXYZ CORP 12/12/2016 
R1 234 qweewwqewewq wqewe 
R1 234 qweewwqewewq wqewe 
R1 234 qweewwqewewq wqewe 
R2 344 dfgdfgdf gfd df g 
HABC LTD 12/12/2016 
R1 234 qweewwqewewq wqewe 
R2 344 dfgdfgdf gfd df g 
HDRE CORP 12/12/2016 
R1 234 qweewwqewewq wqewe 
R2 344 dfgdfgdf gfd df g 
R2 344 dfgdfgdf gfd df g 

Я хочу прочитать набор записей за раз, например.

HDRE CORP 12/12/2016 
R1 234 qweewwqewewq wqewe 
R2 344 dfgdfgdf gfd df g 
R2 344 dfgdfgdf gfd df g 

Как я могу добиться этого иметь в виду, что я не хочу, чтобы держать весь файл в память Есть ли стандартная библиотека, что я могу использовать для этой цели? Я пробовал использовать некоторые реализации без особого успеха, я использовал Line Iterator Apache, но это читается по строкам.

Любая помощь или предложения будут высоко оценены.

+2

Что не так, если вы читаете строки за строкой? –

+2

В любом случае в i/o буферизуется более крупные куски (которые вы обычно можете указать). Часть «строка за строкой» - это просто интерфейс и, вероятно, самый удобный для вашего файла. – pvg

+0

Возможно, я ошибаюсь, поскольку я новичок в этой области. Мое предположение заключается в том, что я не могу читать строки за строкой, потому что между строкой заголовка и строкой заголовка могут быть 3 вида записей R1, R2, R3, которые являются необязательными, повторяемыми и имеют разную ширину. В моем прецеденте требуется прочитать всю запись, установленную за раз. –

ответ

-1

Библиотека для этой цели является BeanIO

Есть много неподдерживаемых библиотеки для формата фиксированного файла там.

Flatpack более поздний, но я не пробовал.

+1

перед тем, как попробовать сторонние библиотеки, изучите, что платформа предлагает из коробки – firephil

1

Данные хранятся по строкам, и вы не знаете, что запись закончилась до тех пор, пока вы не прочтете строку заголовка следующей записи. Вы должны читать строки за строкой. Нечто подобное должно работать:

BufferedReader br = new BufferedReader(new FileReader(file)); 
Vector<String> record = new Vector<>(); 
String line; 

// loop is explicitly broken when file ends 
for (;;) 
{ 
    line = br.readline(); 

    // no more lines - process what's in record and break the loop 
    if (null == line) 
    { 
     ProcessRecord(record); 
     break; 
    } 

    // new header line, process what's in record and clear it 
    // for the new record 
    if (line.startsWith("H")) 
    { 
     ProcessRecord(record); 
     record.clear() 
    } 

    // add the current line to the current record 
    record.add(line); 
} 
1

В Java 8 Использование NIO Files.lines() метод, Stream.map() и PrintWriter.

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

import java.util.stream.Stream; 
import java.io.PrintWriter; 
import java.nio.file.Files; 
import java.nio.file.Paths; 
import java.io.IOException; 

import java.time.LocalDate; 
import java.time.format.DateTimeFormatter;  

public class Main { 

    public static void main(String[] args) { 

     String input = "C://data.txt"; 
     String output = "C://data1.txt"; 
     String date = getDate(); 

     addDate(input,output,date); 

    } 

    public static void addDate(String in, String out,String date) 
    { 

     try (Stream<String> stream = Files.lines(Paths.get(in)); 
      PrintWriter output = new PrintWriter(out, "UTF-8")) 
     {  
     stream.map(x -> { 
      if(x.startsWith("H")) return (x +" "+date); 
      else return x; 
      } 
     ).forEach(output::println); 
     } 
     catch(IOException e){e.printStackTrace();} 
    } 

    public static String getDate(){ 
     DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd/MM/yyyy"); 
     LocalDate localDate = LocalDate.now(); 
     return dtf.format(localDate); 
    } 
} 
+0

Спасибо, это помогает! –

1

Вы должны стремиться к достижению своей цели, используя линию за линией чтения (например, Apache вы использовали или Java8 Files.lines()).

Используйте две петли: внешние, которые обрабатываются до достижения EOF. Внутренний контур для чтения набора записей за раз. После обработки всей записи вы можете отбросить строки, которые вы прочитали, в сборщик мусора. А затем (внешний цикл) обрабатывает следующую запись.

Если вы используете Lambdas и Java 8 F iles.lines(...) - вы можете группировать строки, связанные с одной и той же записью. Затем обработайте эти сгруппированные объекты.

0

Я бы просто пошел со встроенным BufferedReader и прочитал его по очереди.

Я не знаю, что вы имеете в виду фиксированной ширины файла, потому что в вашем комментарии вы говорите, что

R1, R2, R3 все не являются обязательными, повторяемым и имеют различную ширину х.

В любом случае, на основании вашего описания, ваш формат структурирован так

1. Read the first character to get the TOKEN 
2. Check if TOKEN equals "H" or "R" 
3. Split the line and parse it based on what type of TOKEN it is. 

Если R1, R2 и R3 отдельные лексемы, то вам нужно будет проверить является ли это R-вход , а затем, при необходимости, проверьте следующий символ.

Для шага 3 вы можете рассмотреть разбиение на пробелы, если каждое поле в строке разделено пробелом. Или, если каждая запись имеет фиксированную ширину, может быть приемлемо использовать substring для извлечения каждого сегмента.

Я не уверен, что вы подразумеваете под

Мой потребительной случае требует, чтобы прочитать весь рекорд, установленный в то время.

0

Согласно предложению @ firephil, я использовал Java 8 Stream API для этого требования. Я использовал буфер в форме StringBuilder для хранения строк между заголовком и другой записью заголовка. Наконец, вы получите итератор из потока, чтобы получить одну полную запись (H + R1 + R2 + R3) из файла за раз. Проблема с получением последней записи, так как я обрабатываю последнюю запись, теряется, поэтому мне пришлось объединить Fake Record в исходный поток. Это будет сделано для этого времени, однако я уверен, что будет лучший способ обработки.

public static StringBuilder sbTemp; 

public static Iterator<String> process(String in) throws IOException 
{ 
    Iterator<String> recordIterator = null; 
    sbTemp = new StringBuilder(); 
    List<String> fakeRecordList = new ArrayList<String>(); 
    fakeRecordList.add("H Fake Line"); 
    Stream<String> fakeRecordStream = fakeRecordList.stream(); //For getting last Record Set 
    Stream<String> stream = Files.lines(Paths.get(in)).sequential(); 
     Stream<String> finalStream = Stream.concat(stream,fakeRecordStream); 
     // PrintWriter output = new PrintWriter(out, "UTF-8")) 
    {  
     recordIterator = finalStream.map(x -> { 
     if(x.startsWith("H")) { 
      String s = sbTemp.toString(); 
      //System.out.println("Header: "+x); 
      sbTemp = new StringBuilder(); 
      sbTemp.append(x); 
      return s; 
      } 
     else { 
      sbTemp.append("\n").append(x);    
      return ""; 
     } 
    } 
    ).filter(line -> (line.startsWith("H"))).iterator(); 

     System.out.println(recordIterator.next()); 
    } 
    return recordIterator; 
} 

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

  • Нет связанных вопросов^_^