diff --git a/nptdms/reader.py b/nptdms/reader.py index b64d27e..ca86af2 100644 --- a/nptdms/reader.py +++ b/nptdms/reader.py @@ -70,6 +70,11 @@ def __init__(self, tdms_file): self._index_file_path = filepath self._index_file = open(self._index_file_path, "rb") + if self._file is not None: + self._data_file_size = _get_file_size(self._file) + else: + self._data_file_size = None + def close(self): if self._file is None and self._index_file is None: # Already closed @@ -311,24 +316,35 @@ def _read_lead_in(self, file, segment_position, is_index_file=False): # Calculate data and next segment position lead_size = 7 * 4 data_position = segment_position + lead_size + raw_data_offset + data_file_size = self._data_file_size segment_incomplete = next_segment_offset == 0xFFFFFFFFFFFFFFFF if segment_incomplete: # Segment size is unknown. This can happen if LabVIEW crashes. - next_segment_pos = self._get_data_file_size() + next_segment_pos = data_file_size + else: + next_segment_pos = ( + segment_position + next_segment_offset + lead_size) + if data_file_size is not None and next_segment_pos > data_file_size: + # The raw data offset is incorrect, and there is less data than expected in this segment + next_segment_pos = data_file_size + segment_incomplete = True + + if segment_incomplete: if next_segment_pos < data_position: # Metadata wasn't completely written and don't have any data in this segment, # don't try to read any metadata log.warning("Last segment metadata is incomplete") raise EOFError - # Try to read until the end of the file if we have complete metadata - log.warning( - "Last segment of file has unknown size, " - "will attempt to read to the end of the file") - else: - log.debug("Next segment offset = %d, raw data offset = %d, data size = %d b", - next_segment_offset, raw_data_offset, next_segment_offset - raw_data_offset) - next_segment_pos = ( - segment_position + next_segment_offset + lead_size) + else: + # Try to read until the end of the file if we have complete metadata + log.warning( + "Last segment of file has less data than expected, " + "will attempt to read to the end of the file") + + log.debug("Next segment offset = %d, raw data offset = %d, expected data size = %d b, actual data size = %d b", + next_segment_offset, raw_data_offset, + next_segment_offset - raw_data_offset, + next_segment_pos - data_position) return segment_position, toc_mask, data_position, next_segment_pos, segment_incomplete @@ -346,13 +362,6 @@ def _verify_segment_start(self, segment): position) + "Check that the tdms_index file matches the tdms data file.") - def _get_data_file_size(self): - current_pos = self._file.tell() - self._file.seek(0, os.SEEK_END) - end_pos = self._file.tell() - self._file.seek(current_pos, os.SEEK_SET) - return end_pos - def _update_object_metadata(self, segment): """ Update object metadata using the metadata read from a single segment """ @@ -509,3 +518,11 @@ def _array_equal(a, b, chunk_size=100): if not (a[offset:offset+chunk_size] == b[offset:offset+chunk_size]).all(): return False return True + + +def _get_file_size(file): + current_pos = file.tell() + file.seek(0, os.SEEK_END) + end_pos = file.tell() + file.seek(current_pos, os.SEEK_SET) + return end_pos