Skip to content

Commit 3bf11e5

Browse files
authored
Merge pull request #45 from cta-observatory/fix-zstd
Fix reading of zstd compressed files (no backseeking in iter_blocks)
2 parents e224a7a + d573ae4 commit 3bf11e5

3 files changed

Lines changed: 59 additions & 6 deletions

File tree

corsikaio/io.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,32 +61,41 @@ def read_buffer_size(path):
6161

6262
def iter_blocks(f, thinning=False):
6363
is_fortran_file = True
64-
if thinning == False:
64+
if not thinning:
6565
block_size = BLOCK_SIZE_BYTES
6666
buffer_size = DEFAULT_BUFFER_SIZE
6767
else:
6868
block_size = BLOCK_SIZE_BYTES_THIN
6969
buffer_size = DEFAULT_BUFFER_SIZE_THIN
7070

71-
7271
data = f.read(4)
73-
f.seek(0)
72+
first = True
7473
if data == b'RUNH':
7574
is_fortran_file = False
7675

7776
while True:
7877
# for the fortran-chunked output, we need to read the record size
7978
if is_fortran_file:
80-
data = f.read(RECORD_MARKER.size)
79+
if first is True:
80+
data = data + f.read(RECORD_MARKER.size - len(data))
81+
else:
82+
data = f.read(RECORD_MARKER.size)
83+
8184
if len(data) == 0:
8285
return
8386

8487
if len(data) < RECORD_MARKER.size:
8588
raise IOError("Read less bytes than expected, file seems to be truncated")
8689

8790
buffer_size, = RECORD_MARKER.unpack(data)
91+
data = b""
92+
93+
if first is True:
94+
data = data + f.read(buffer_size - len(data))
95+
first = False
96+
else:
97+
data = f.read(buffer_size)
8898

89-
data = f.read(buffer_size)
9099
if is_fortran_file:
91100
if len(data) < buffer_size:
92101
raise IOError("Read less bytes than expected, file seems to be truncated")

setup.cfg

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ zstd =
2525
zstandard
2626
tests =
2727
pytest
28-
scipy
28+
scipy
29+
zstandard
2930
all =
3031
%(zstd)s
3132
%(tests)s

tests/test_file.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1+
from contextlib import ExitStack
2+
import gzip
3+
from pathlib import Path
4+
15
import pytest
26
import numpy as np
37

8+
from zstandard import ZstdCompressor
9+
410
from corsikaio.constants import BLOCK_SIZE_BYTES
511
from corsikaio.io import RECORD_MARKER
612

@@ -167,3 +173,40 @@ def test_longitudinal_parameters():
167173
parameters = event.end["longitudinal_fit_parameters"]
168174
np.testing.assert_array_equal(parameters != 0, True)
169175
assert n_events == 5
176+
177+
178+
@pytest.mark.parametrize (
179+
"test_path",
180+
[
181+
'tests/resources/mmcs65',
182+
'tests/resources/corsika74100',
183+
]
184+
)
185+
@pytest.mark.parametrize( "compression", ["gz", "zst"])
186+
def test_compressed(test_path, compression, tmp_path):
187+
from corsikaio import CorsikaCherenkovFile
188+
189+
test_path = Path(test_path)
190+
compressed = tmp_path / f"{test_path.name}.{compression}"
191+
192+
ctx = ExitStack()
193+
194+
with ctx:
195+
infile = ctx.enter_context(test_path.open("rb"))
196+
outfile = ctx.enter_context(compressed.open("wb"))
197+
198+
if compression == "gz":
199+
outstream = ctx.enter_context(gzip.GzipFile(fileobj=outfile, mode="wb"))
200+
elif compression == "zst":
201+
compressor = ZstdCompressor(level=10)
202+
outstream = ctx.enter_context(compressor.stream_writer(outfile))
203+
else:
204+
raise ValueError(f"Unknown compression: {compression}")
205+
206+
for chunk in iter(lambda : infile.read(102400), b""):
207+
outstream.write(chunk)
208+
209+
with CorsikaCherenkovFile(compressed) as cf, CorsikaCherenkovFile(test_path) as f:
210+
for event in f:
211+
compressed_event = next(cf)
212+
assert event.header["event_number"] == compressed_event.header["event_number"]

0 commit comments

Comments
 (0)