Files
x11ma/plugins/fiji/sparseviewer/io/TxtTableReader.java
T
2026-06-24 13:28:45 +02:00

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;
}
}