/* * Copyright (c) 2013-2015 mgm technology partners GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.mgmtp.perfload.perfalyzer.util; import static com.google.common.collect.Iterators.mergeSorted; import static com.google.common.io.Files.createParentDirs; import static com.mgmtp.perfload.perfalyzer.util.IoUtilities.writeLineToChannel; import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.channels.FileChannel; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Scanner; import java.util.Set; import com.google.common.collect.ImmutableSet; /** * Merges multiple CSV files into a single one. * * @author rnaegele */ public class CsvFileSortMerger { private final Set<File> sourceFiles; private final File destFile; private final Comparator<String> comparator; /** * @param sourceFiles * the set of source files to be merged * @param destFile * the destination file * @param comparator * the comparator to use for sorting */ public CsvFileSortMerger(final Set<File> sourceFiles, final File destFile, final Comparator<String> comparator) { this.comparator = comparator; this.sourceFiles = ImmutableSet.copyOf(sourceFiles); this.destFile = destFile; } /** * Merges the files specified in the constructor into the destination file. */ public void mergeFiles() throws IOException { createParentDirs(destFile); List<Slot> slots = new ArrayList<>(sourceFiles.size()); for (File file : sourceFiles) { Slot slot = Slot.openSlot(file); slots.add(slot); } try (final FileOutputStream fis = new FileOutputStream(destFile)) { FileChannel writeChannel = fis.getChannel(); mergeSorted(slots, comparator).forEachRemaining(line -> writeLineToChannel(writeChannel, line, Charset.forName("UTF-8"))); } finally { slots.forEach(Slot::close); } } static class Slot implements Closeable, Iterator<String> { private final File file; private FileInputStream inputStream; private Scanner scanner; private Slot(final File file) { this.file = file; } public static Slot openSlot(final File file) { Slot slot = new Slot(file); slot.doOpen(); return slot; } private void doOpen() { try { if (inputStream == null) { inputStream = new FileInputStream(file); scanner = new Scanner(inputStream); } } catch (FileNotFoundException ex) { throw new UncheckedIOException(ex); } } /** * Closes the internally used {@link Scanner} and {@link java.io.InputStream}. */ @Override public void close() { try { if (scanner != null) { scanner.close(); } if (inputStream != null) { inputStream.close(); } } catch (IOException ex) { throw new UncheckedIOException(ex); } } @Override public boolean hasNext() { return scanner.hasNext(); } @Override public String next() { return scanner.nextLine(); } } }