从本地存储带Flag的Log文件提取指定数据并分段绘图求助
Got it, let's walk through how to solve this problem step by step. You’ve already got the logging system up and running on your console device—now we just need to parse those log files, filter the right entries, split them into time-based segments, and prep the data for plotting.
First, we’ll create a helper class to store each valid log entry, then write code to read the log file line by line, parse each field, and only keep entries where the Flag is 1.
Define a Data Class for Log Entries
This will make it easier to handle and manipulate the data later:
public class LogEntry { private double pdMeanValue; private double aoMean; private double aoMap; private double ffrValue; private double ffrLowestValue; private Date timestamp; private int flag; // Constructor public LogEntry(double pdMeanValue, double aoMean, double aoMap, double ffrValue, double ffrLowestValue, Date timestamp, int flag) { this.pdMeanValue = pdMeanValue; this.aoMean = aoMean; this.aoMap = aoMap; this.ffrValue = ffrValue; this.ffrLowestValue = ffrLowestValue; this.timestamp = timestamp; this.flag = flag; } // Getters (required to access fields later) public double getPdMeanValue() { return pdMeanValue; } public double getAoMean() { return aoMean; } public double getAoMap() { return aoMap; } public Date getTimestamp() { return timestamp; } // Add getters for other fields as needed }
Parse & Filter the Log File
Make sure to use the exact same date formatter you used when writing the log (your mFormatter variable). If you can’t recall its pattern, check where it’s defined in your original code—using the wrong pattern will cause parsing errors.
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import java.util.Locale; public List<LogEntry> parseAndFilterLog(String filePath) throws IOException, ParseException { List<LogEntry> validEntries = new ArrayList<>(); // Replace this with your actual mFormatter pattern from the logging code SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMdd_HHmmss_SSS", Locale.US); try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) { String line; while ((line = reader.readLine()) != null) { String[] parts = line.split("\\|"); // Skip invalid lines that don't match the expected 7-part format if (parts.length != 7) continue; // Parse each field, converting empty strings back to -1 (matches your logging logic) double pdMean = parts[0].isEmpty() ? -1 : Double.parseDouble(parts[0]); double aoMean = parts[1].isEmpty() ? -1 : Double.parseDouble(parts[1]); double aoMap = parts[2].isEmpty() ? -1 : Double.parseDouble(parts[2]); double ffrValue = parts[3].isEmpty() ? -1 : Double.parseDouble(parts[3]); double ffrLowest = parts[4].isEmpty() ? -1 : Double.parseDouble(parts[4]); Date timestamp = dateFormatter.parse(parts[5]); int flag = Integer.parseInt(parts[6]); // Only keep entries where Flag is 1 if (flag == 1) { validEntries.add(new LogEntry(pdMean, aoMean, aoMap, ffrValue, ffrLowest, timestamp, flag)); } } } return validEntries; }
Next, we’ll split the filtered entries into time-based segments. We’ll cover two common use cases: fixed-duration intervals (e.g., every 1 minute) and custom time ranges.
Option A: Fixed-Duration Segments (e.g., Every X Minutes)
This groups entries into equal time blocks (adjust the interval to your needs):
import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.TreeMap; public Map<Long, List<LogEntry>> segmentByFixedInterval(List<LogEntry> entries, long intervalMillis) { // Sort entries by timestamp first to ensure order entries.sort(Comparator.comparing(LogEntry::getTimestamp)); // TreeMap keeps intervals sorted chronologically Map<Long, List<LogEntry>> segmentedEntries = new TreeMap<>(); for (LogEntry entry : entries) { // Calculate the start time of the interval this entry belongs to long intervalKey = entry.getTimestamp().getTime() / intervalMillis * intervalMillis; segmentedEntries.computeIfAbsent(intervalKey, k -> new ArrayList<>()).add(entry); } return segmentedEntries; } // Usage example: Segment into 1-minute intervals (60,000 milliseconds) // Map<Long, List<LogEntry>> minuteSegments = segmentByFixedInterval(validEntries, 60 * 1000);
Option B: Custom Time Ranges
If you need to split entries into specific date ranges (e.g., 10:00-10:30 AM, 10:30-11:00 AM), use this approach:
import java.util.ArrayList; import java.util.Comparator; import java.util.List; public List<List<LogEntry>> segmentByCustomRanges(List<LogEntry> entries, List<DateRange> ranges) { List<List<LogEntry>> segmented = new ArrayList<>(); entries.sort(Comparator.comparing(LogEntry::getTimestamp)); for (DateRange range : ranges) { List<LogEntry> rangeEntries = new ArrayList<>(); for (LogEntry entry : entries) { Date ts = entry.getTimestamp(); if (ts.after(range.getStart()) && ts.before(range.getEnd())) { rangeEntries.add(entry); } } segmented.add(rangeEntries); } return segmented; } // Helper class to define custom date ranges class DateRange { private Date start; private Date end; public DateRange(Date start, Date end) { this.start = start; this.end = end; } public Date getStart() { return start; } public Date getEnd() { return end; } }
Now you can extract the fields you need (pdMeanValue, aoMean, etc.) and format them for your charting library. Below is an example using MPAndroidChart (common for Android devices), but the logic translates to other libraries like JFreeChart.
Create Data Sets for Charting
import com.github.mikephil.charting.data.Entry; import com.github.mikephil.charting.data.LineDataSet; import java.util.ArrayList; import java.util.List; public LineDataSet createChartDataSet(List<LogEntry> entries, String label, String fieldName) { List<Entry> chartEntries = new ArrayList<>(); for (int i = 0; i < entries.size(); i++) { LogEntry entry = entries.get(i); double value = switch (fieldName) { case "pdMeanValue" -> entry.getPdMeanValue(); case "aoMean" -> entry.getAoMean(); case "aoMap" -> entry.getAoMap(); // Add cases for other fields you want to plot default -> 0; }; // Use index as X-value, or convert timestamp to a numeric X-value if preferred chartEntries.add(new Entry(i, (float) value)); } LineDataSet dataSet = new LineDataSet(chartEntries, label); // Customize appearance (colors, line width, etc.) as needed dataSet.setColor(R.color.blue); dataSet.setLineWidth(2f); return dataSet; }
Assemble & Display the Chart
import com.github.mikephil.charting.charts.LineChart; import com.github.mikephil.charting.data.LineData; // Example: Plot PD Mean and AO Mean for a single time segment public void plotSegmentData(LineChart chart, List<LogEntry> segmentEntries) { LineDataSet pdMeanSet = createChartDataSet(segmentEntries, "PD Mean", "pdMeanValue"); LineDataSet aoMeanSet = createChartDataSet(segmentEntries, "AO Mean", "aoMean"); LineData lineData = new LineData(pdMeanSet, aoMeanSet); chart.setData(lineData); chart.getDescription().setText("Time Segment Data"); chart.invalidate(); // Refresh the chart }
- Formatter Consistency: Double-check that your date parsing formatter matches exactly what you used when writing logs. Mismatched patterns will cause
ParseExceptions. - Missing Values: Handle
-1values appropriately in your chart (e.g., skip them or plot as empty points) to avoid skewing your visualization. - Performance: For large log files, consider streaming the file instead of loading all entries into memory at once to prevent out-of-memory errors.
- Sorting: Always sort entries by timestamp before segmenting to ensure your time intervals are in chronological order.
内容的提问来源于stack exchange,提问作者Sourav Pany

