| | |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import java.io.ByteArrayOutputStream; |
| | | import java.io.RandomAccessFile; |
| | | import java.nio.charset.StandardCharsets; |
| | | import java.nio.file.Files; |
| | | import java.nio.file.Path; |
| | |
| | | } |
| | | for (DeviceAggregate aggregate : aggregateMap.values()) { |
| | | if (aggregate.firstFile != null) { |
| | | FileTimeRange firstRange = readFileTimeRange(aggregate.firstFile); |
| | | FileTimeRange firstRange = readFileTimeRange(aggregate.firstFile, aggregate.stationId); |
| | | aggregate.firstTime = firstRange.startTime != null ? firstRange.startTime : firstRange.endTime; |
| | | } |
| | | if (aggregate.lastFile != null) { |
| | | FileTimeRange lastRange = readFileTimeRange(aggregate.lastFile); |
| | | FileTimeRange lastRange = readFileTimeRange(aggregate.lastFile, aggregate.stationId); |
| | | aggregate.lastTime = lastRange.endTime != null ? lastRange.endTime : lastRange.startTime; |
| | | } |
| | | } |
| | |
| | | List<Map<String, Object>> segments = new ArrayList<>(); |
| | | Long startTime = null; |
| | | for (int i = 0; i < files.size(); i++) { |
| | | Long segmentStart = getFileStartTime(files.get(i)); |
| | | Long segmentStart = getFileStartTime(files.get(i), stationId); |
| | | if (segmentStart != null && (startTime == null || segmentStart < startTime)) { |
| | | startTime = segmentStart; |
| | | } |
| | |
| | | segment.put("endTime", null); |
| | | segments.add(segment); |
| | | } |
| | | Long endTime = getFileEndTime(files.get(files.size() - 1)); |
| | | Long endTime = getFileEndTime(files.get(files.size() - 1), stationId); |
| | | if (endTime == null) { |
| | | for (int i = segments.size() - 1; i >= 0; i--) { |
| | | Long segmentStart = (Long) segments.get(i).get("startTime"); |
| | |
| | | if (line != null && !line.trim().isEmpty()) { |
| | | try { |
| | | DeviceDataLog logItem = JSON.parseObject(line, DeviceDataLog.class); |
| | | resultLogs.add(logItem); |
| | | if (matchesRequestedStation(logItem, stationId)) { |
| | | resultLogs.add(logItem); |
| | | } |
| | | } catch (Exception e) { |
| | | } |
| | | } |
| | |
| | | while (low <= high) { |
| | | int mid = (low + high) >>> 1; |
| | | Path midFile = files.get(mid); |
| | | Long midStart = getFileStartTime(midFile); |
| | | Long midStart = getFileStartTime(midFile, stationId); |
| | | if (midStart == null) { |
| | | low = mid + 1; |
| | | continue; |
| | |
| | | } |
| | | } |
| | | |
| | | private Long getFileStartTime(Path file) { |
| | | private Long getFileStartTime(Path file, String stationId) { |
| | | try { |
| | | String firstLine = readFirstNonBlankLine(file); |
| | | String firstLine = readFirstMatchingLine(file, stationId); |
| | | if (firstLine == null) return null; |
| | | DeviceDataLog firstLog = JSON.parseObject(firstLine, DeviceDataLog.class); |
| | | return firstLog.getCreateTime().getTime(); |
| | |
| | | } |
| | | } |
| | | |
| | | private Long getFileEndTime(Path file) { |
| | | private Long getFileEndTime(Path file, String stationId) { |
| | | try { |
| | | String lastLine = readLastNonBlankLine(file); |
| | | String lastLine = readLastMatchingLine(file, stationId); |
| | | if (lastLine == null) return null; |
| | | DeviceDataLog lastLog = JSON.parseObject(lastLine, DeviceDataLog.class); |
| | | return lastLog.getCreateTime().getTime(); |
| | |
| | | } |
| | | } |
| | | |
| | | private FileTimeRange readFileTimeRange(Path file) { |
| | | private FileTimeRange readFileTimeRange(Path file, String stationId) { |
| | | FileTimeRange range = new FileTimeRange(); |
| | | try { |
| | | String firstLine = readFirstNonBlankLine(file); |
| | | String lastLine = readLastNonBlankLine(file); |
| | | range.startTime = parseLogTime(firstLine); |
| | | range.endTime = parseLogTime(lastLine); |
| | | String firstLine = readFirstMatchingLine(file, stationId); |
| | | String lastLine = readLastMatchingLine(file, stationId); |
| | | range.startTime = parseLogTime(firstLine, stationId); |
| | | range.endTime = parseLogTime(lastLine, stationId); |
| | | return range; |
| | | } catch (Exception e) { |
| | | return range; |
| | | } |
| | | } |
| | | |
| | | private Long parseLogTime(String line) { |
| | | private Long parseLogTime(String line, String stationId) { |
| | | try { |
| | | if (line == null || line.trim().isEmpty()) { |
| | | return null; |
| | | } |
| | | DeviceDataLog logItem = JSON.parseObject(line, DeviceDataLog.class); |
| | | if (!matchesRequestedStation(logItem, stationId)) { |
| | | return null; |
| | | } |
| | | return logItem != null && logItem.getCreateTime() != null ? logItem.getCreateTime().getTime() : null; |
| | | } catch (Exception e) { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | private String readFirstNonBlankLine(Path file) { |
| | | private boolean matchesRequestedStation(DeviceDataLog logItem, String stationId) { |
| | | if (Cools.isEmpty(stationId)) { |
| | | return true; |
| | | } |
| | | if (logItem == null || logItem.getStationId() == null) { |
| | | return false; |
| | | } |
| | | return Objects.equals(String.valueOf(logItem.getStationId()), stationId); |
| | | } |
| | | |
| | | private String readFirstMatchingLine(Path file, String stationId) { |
| | | try (Stream<String> lines = Files.lines(file, StandardCharsets.UTF_8)) { |
| | | return lines.filter(line -> line != null && !line.trim().isEmpty()).findFirst().orElse(null); |
| | | return lines |
| | | .filter(line -> line != null && !line.trim().isEmpty()) |
| | | .filter(line -> matchesRequestedStation(parseLogLine(line), stationId)) |
| | | .findFirst() |
| | | .orElse(null); |
| | | } catch (Exception e) { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | private String readLastNonBlankLine(Path file) { |
| | | try (RandomAccessFile randomAccessFile = new RandomAccessFile(file.toFile(), "r")) { |
| | | long length = randomAccessFile.length(); |
| | | if (length <= 0) { |
| | | private String readLastMatchingLine(Path file, String stationId) { |
| | | try (Stream<String> lines = Files.lines(file, StandardCharsets.UTF_8)) { |
| | | List<String> matched = lines |
| | | .filter(line -> line != null && !line.trim().isEmpty()) |
| | | .filter(line -> matchesRequestedStation(parseLogLine(line), stationId)) |
| | | .collect(Collectors.toList()); |
| | | if (matched.isEmpty()) { |
| | | return null; |
| | | } |
| | | ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| | | for (long pointer = length - 1; pointer >= 0; pointer--) { |
| | | randomAccessFile.seek(pointer); |
| | | int read = randomAccessFile.read(); |
| | | if (read == '\n' || read == '\r') { |
| | | if (baos.size() > 0) { |
| | | break; |
| | | } |
| | | continue; |
| | | } |
| | | baos.write(read); |
| | | return matched.get(matched.size() - 1); |
| | | } catch (Exception e) { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | private DeviceDataLog parseLogLine(String line) { |
| | | try { |
| | | if (line == null || line.trim().isEmpty()) { |
| | | return null; |
| | | } |
| | | byte[] bytes = baos.toByteArray(); |
| | | for (int i = 0, j = bytes.length - 1; i < j; i++, j--) { |
| | | byte tmp = bytes[i]; |
| | | bytes[i] = bytes[j]; |
| | | bytes[j] = tmp; |
| | | } |
| | | String line = new String(bytes, StandardCharsets.UTF_8).trim(); |
| | | return line.isEmpty() ? null : line; |
| | | return JSON.parseObject(line, DeviceDataLog.class); |
| | | } catch (Exception e) { |
| | | return null; |
| | | } |