package importexport.exporting; import importexport.util.CSVFileInfo; import importexport.util.InvalidFileException; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.nio.BufferOverflowException; import controller.DataHub; import controller.ElementData; import controller.Feature; import controller.SelectionController; import controller.SubspaceController; import db.DatabaseAccessException; /** * {@inheritDoc} */ public class CSVBasedExporter extends Exporter { /** * Creates a new Exporter for any csv-based formatted file * (e.g. ".csv" or ".arff"). * * @param datahub * used to get the data which should be exported. * @param selectionController * used to extract the current selection. * @param subspaceController * used to get all necessary information about the subspaces. * @param concreteInjector * injector which is used to create the file headers. */ public CSVBasedExporter(final DataHub datahub, final SelectionController selectionController, final SubspaceController subspaceController, final FileInfoInjector concreteInjector) { super(datahub, selectionController, subspaceController, concreteInjector); } /** * {@inheritDoc} */ @Override public void exportFile(final File output, final boolean wOutlierness) throws InvalidFileException, IOException, DatabaseAccessException { if (output == null) { throw new InvalidFileException(); } SelectionController selCon = this.getSelectionController(); BufferedWriter bw = new BufferedWriter(new FileWriter(output)); CSVFileInfo fInfo = createFileInfo(output); Feature[] feats = this.getSubspaceController().getSubspaces()[0].getFeatures(); this.getInjector().injectFileInfo(bw, fInfo, feats); ElementData[] data = this.getDatahub().getData(); int bufferSize = 0; boolean flushStream = false; if (selCon.isSomethingSelected()) { int[] selection = selCon.getSelection(); for (int selectedItem : selection) { if (++bufferSize == FLASH_AT) { bufferSize = 0; flushStream = true; } writeLine(buildLine(data[selectedItem - 1]), bw, flushStream); } } else { for (ElementData d : data) { if (++bufferSize == FLASH_AT) { bufferSize = 0; flushStream = true; } writeLine(buildLine(d), bw, flushStream); } } bw.close(); if (wOutlierness) { /* get from UI always a file with a valid file extendsion like ".arff", * so e.g. ".arff" will be replaced by ".ssd". */ int lastDotOfOutput = output.getAbsolutePath().lastIndexOf('.'); StringBuilder ssdFileName = new StringBuilder(output.getAbsolutePath()); ssdFileName.delete(lastDotOfOutput, ssdFileName.length()); ssdFileName.append(".ssd"); this.exportSSD(new File(ssdFileName.toString())); } } /** * Builds a line which should be written into the csv-based file, * based on the informations of an object of class {@link ElementData}. * @param d * ElementData object which should be exported * @return * The built line. * @throws DatabaseAccessException * Threw if access to current database is failed. */ private StringBuilder buildLine(final ElementData d) throws DatabaseAccessException { StringBuilder sb = new StringBuilder(); Feature[] feats = this.getSubspaceController().getActiveSubspace().getFeatures(); Float tmp; for (Feature f : feats) { if (!f.isOutlier() && !f.isVirtual()) { tmp = d.getValue(f); if (tmp.isNaN()) { sb.append("?,"); } else { sb.append((d.getValue(f) + ",")); } } } if (getInjector() instanceof ArffFileInfoInjector) { sb.append("0"); } else { sb.deleteCharAt(sb.length() - 1); } return sb; } /** * Writes previous built {@link CharSequence} into a file. * * @param cs * {@link CharSequence} which should be written to file. * @param bw * {@link BufferOverflowException} which is responsible for * write action. * @param flush * true if writer stream should be flushed after write action. * @throws IOException * threw if an arbitrary io-operation failed. */ private void writeLine(final CharSequence cs, final BufferedWriter bw, boolean flush) throws IOException { bw.write(cs.toString()); bw.newLine(); if (flush) { bw.flush(); } } /** * Creates {@link CSVFileInfo} which for in future exported file. * @param f * File for what the {@link CSVFileInfo} is built for. * @return * The constructed {@link CSVFileInfo} object. * @throws DatabaseAccessException * Threw if access to current database is failed. */ private CSVFileInfo createFileInfo(final File f) throws DatabaseAccessException { String relation = f.getName(); Feature[] features = this.getSubspaceController().getSubspaces()[0].getFeatures(); String[] featureNames = new String[features.length]; for (int i = 1; i < features.length; ++i) { featureNames[i] = features[i].getName(); } //fLODS = first line of data segment. int fLODS = -1; FileInfoInjector injector = this.getInjector(); if (injector instanceof ArffFileInfoInjector) { fLODS = 4 + features.length; } else if (injector instanceof CSVFileInfoInjector) { fLODS = 2; } return new CSVFileInfo(relation, featureNames, fLODS, ','); } }