216 lines
6.3 KiB
Java
216 lines
6.3 KiB
Java
package sparseviewer.io;
|
|
|
|
import sparseviewer.model.ScanDataset;
|
|
import ij.IJ;
|
|
|
|
import java.io.BufferedReader;
|
|
import java.io.File;
|
|
import java.io.FileReader;
|
|
import java.io.IOException;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.Vector;
|
|
|
|
public class TxtTableReader {
|
|
|
|
public static ScanDataset readFiles(List<File> files) throws IOException {
|
|
if (files == null || files.isEmpty()) {
|
|
throw new IOException("No files selected.");
|
|
}
|
|
|
|
String[] referenceHeader = null;
|
|
|
|
List<double[]> allRows = new ArrayList<double[]>();
|
|
List<Integer> fileIndices = new ArrayList<Integer>();
|
|
|
|
for (int fileIdx = 0; fileIdx < files.size(); fileIdx++) {
|
|
File file = files.get(fileIdx);
|
|
ParsedTxt parsed = readSingleFile(file);
|
|
|
|
if (referenceHeader == null) {
|
|
referenceHeader = parsed.channelNames;
|
|
} else {
|
|
if (!sameHeader(referenceHeader, parsed.channelNames)) {
|
|
throw new IOException(
|
|
"Header mismatch in file:\n" + file.getAbsolutePath()
|
|
);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < parsed.rows.size(); i++) {
|
|
allRows.add(parsed.rows.get(i));
|
|
fileIndices.add(Integer.valueOf(fileIdx));
|
|
}
|
|
}
|
|
|
|
int rowCount = allRows.size();
|
|
int colCount = referenceHeader.length;
|
|
|
|
double[][] columns = new double[colCount][rowCount];
|
|
int[] fileIndex = new int[rowCount];
|
|
|
|
for (int r = 0; r < rowCount; r++) {
|
|
double[] row = allRows.get(r);
|
|
|
|
for (int c = 0; c < colCount; c++) {
|
|
columns[c][r] = row[c];
|
|
}
|
|
|
|
fileIndex[r] = fileIndices.get(r).intValue();
|
|
}
|
|
|
|
IJ.log("Sparse Scan Viewer: loaded " + files.size()
|
|
+ " file(s), " + rowCount
|
|
+ " rows, " + colCount + " channels.");
|
|
|
|
return new ScanDataset(referenceHeader, columns, rowCount, fileIndex, files);
|
|
}
|
|
|
|
private static ParsedTxt readSingleFile(File file) throws IOException {
|
|
BufferedReader br = null;
|
|
|
|
try {
|
|
br = new BufferedReader(new FileReader(file));
|
|
|
|
String line;
|
|
String[] channels = null;
|
|
int expectedRows = -1;
|
|
List<double[]> rows = new ArrayList<double[]>();
|
|
|
|
while ((line = br.readLine()) != null) {
|
|
String trimmed = line.trim();
|
|
|
|
if (trimmed.length() == 0) {
|
|
continue;
|
|
}
|
|
|
|
if (trimmed.startsWith("#table[")) {
|
|
HeaderInfo info = parseHeader(trimmed);
|
|
channels = info.channelNames;
|
|
expectedRows = info.expectedRows;
|
|
continue;
|
|
}
|
|
|
|
if (trimmed.startsWith("#")) {
|
|
continue;
|
|
}
|
|
|
|
if (channels == null) {
|
|
continue;
|
|
}
|
|
|
|
String[] parts = trimmed.split(";");
|
|
|
|
if (parts.length < channels.length) {
|
|
continue;
|
|
}
|
|
|
|
double[] row = new double[channels.length];
|
|
boolean valid = true;
|
|
|
|
for (int i = 0; i < channels.length; i++) {
|
|
try {
|
|
row[i] = Double.parseDouble(parts[i].trim());
|
|
} catch (NumberFormatException e) {
|
|
valid = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (valid) {
|
|
rows.add(row);
|
|
}
|
|
}
|
|
|
|
if (channels == null) {
|
|
throw new IOException("No #table[...] header found in " + file.getName());
|
|
}
|
|
|
|
if (expectedRows >= 0 && expectedRows != rows.size()) {
|
|
IJ.log("Warning: " + file.getName()
|
|
+ " header says " + expectedRows
|
|
+ " rows, but parsed " + rows.size() + " rows.");
|
|
}
|
|
|
|
ParsedTxt parsed = new ParsedTxt();
|
|
parsed.channelNames = channels;
|
|
parsed.rows = rows;
|
|
return parsed;
|
|
|
|
} finally {
|
|
if (br != null) {
|
|
try {
|
|
br.close();
|
|
} catch (IOException ignored) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static HeaderInfo parseHeader(String line) throws IOException {
|
|
int open = line.indexOf('[');
|
|
int close = line.indexOf(']');
|
|
|
|
if (open < 0 || close < 0 || close <= open) {
|
|
throw new IOException("Invalid #table header:\n" + line);
|
|
}
|
|
|
|
int expectedRows = -1;
|
|
|
|
try {
|
|
expectedRows = Integer.parseInt(line.substring(open + 1, close).trim());
|
|
} catch (Exception ignored) {
|
|
}
|
|
|
|
String rest = line.substring(close + 1).trim();
|
|
String[] rawChannels = rest.split(";");
|
|
|
|
Vector<String> names = new Vector<String>();
|
|
|
|
for (int i = 0; i < rawChannels.length; i++) {
|
|
String name = rawChannels[i].trim();
|
|
|
|
if (name.length() > 0) {
|
|
names.add(name);
|
|
}
|
|
}
|
|
|
|
if (names.isEmpty()) {
|
|
throw new IOException("No channels found in header:\n" + line);
|
|
}
|
|
|
|
HeaderInfo info = new HeaderInfo();
|
|
info.expectedRows = expectedRows;
|
|
info.channelNames = names.toArray(new String[names.size()]);
|
|
return info;
|
|
}
|
|
|
|
private static boolean sameHeader(String[] a, String[] b) {
|
|
if (a == null || b == null) {
|
|
return false;
|
|
}
|
|
|
|
if (a.length != b.length) {
|
|
return false;
|
|
}
|
|
|
|
for (int i = 0; i < a.length; i++) {
|
|
if (!a[i].equals(b[i])) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private static class HeaderInfo {
|
|
int expectedRows;
|
|
String[] channelNames;
|
|
}
|
|
|
|
private static class ParsedTxt {
|
|
String[] channelNames;
|
|
List<double[]> rows;
|
|
}
|
|
} |