Skip to content

Commit c48abd0

Browse files
committed
write file
1 parent 35a8e4f commit c48abd0

File tree

3 files changed

+71
-18
lines changed

3 files changed

+71
-18
lines changed

wfdb/io/_signal.py

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import math
2+
import io
23
import os
34
import posixpath
45
import sys
@@ -120,7 +121,7 @@ class SignalMixin(object):
120121
121122
"""
122123

123-
def wr_dats(self, expanded, write_dir):
124+
def wr_dats(self, expanded, write_dir, wfdb_archive=None):
124125
"""
125126
Write all dat files associated with a record
126127
expanded=True to use e_d_signal instead of d_signal.
@@ -132,6 +133,8 @@ def wr_dats(self, expanded, write_dir):
132133
the `d_signal` attribute (False).
133134
write_dir : str
134135
The directory to write the output file to.
136+
wfdb_archive : WFDBArchive, optional
137+
If set, writes to a .wfdb archive instead of the filesystem.
135138
136139
Returns
137140
-------
@@ -160,7 +163,8 @@ def wr_dats(self, expanded, write_dir):
160163
self.check_sig_cohesion([], expanded)
161164

162165
# Write each of the specified dat files
163-
self.wr_dat_files(expanded=expanded, write_dir=write_dir)
166+
self.wr_dat_files(expanded=expanded, write_dir=write_dir,
167+
wfdb_archive=wfdb_archive)
164168

165169
def check_sig_cohesion(self, write_fields, expanded):
166170
"""
@@ -958,7 +962,7 @@ def calc_checksum(self, expanded=False):
958962
cs = [int(c) for c in cs]
959963
return cs
960964

961-
def wr_dat_files(self, expanded=False, write_dir=""):
965+
def wr_dat_files(self, expanded=False, write_dir="", wfdb_archive=None):
962966
"""
963967
Write each of the specified dat files.
964968
@@ -969,6 +973,8 @@ def wr_dat_files(self, expanded=False, write_dir=""):
969973
the `d_signal` attribute (False).
970974
write_dir : str, optional
971975
The directory to write the output file to.
976+
wfdb_archive : WFDBArchive, optional
977+
If set, writes to a .wfdb archive instead of the local filesystem.
972978
973979
Returns
974980
-------
@@ -1003,6 +1009,7 @@ def wr_dat_files(self, expanded=False, write_dir=""):
10031009
[self.e_d_signal[ch] for ch in dat_channels[fn]],
10041010
[self.samps_per_frame[ch] for ch in dat_channels[fn]],
10051011
write_dir=write_dir,
1012+
wfdb_archive=wfdb_archive,
10061013
)
10071014
else:
10081015
dsig = self.d_signal
@@ -1013,6 +1020,7 @@ def wr_dat_files(self, expanded=False, write_dir=""):
10131020
dsig[:, dat_channels[fn][0] : dat_channels[fn][-1] + 1],
10141021
dat_offsets[fn],
10151022
write_dir=write_dir,
1023+
wfdb_archive=wfdb_archive,
10161024
)
10171025

10181026
def smooth_frames(self, sigtype="physical"):
@@ -2322,6 +2330,7 @@ def wr_dat_file(
23222330
e_d_signal=None,
23232331
samps_per_frame=None,
23242332
write_dir="",
2333+
wfdb_archive=None,
23252334
):
23262335
"""
23272336
Write a dat file. All bytes are written one at a time to avoid
@@ -2519,16 +2528,30 @@ def wr_dat_file(
25192528
else:
25202529
raise ValueError(f"unknown format ({fmt})")
25212530

2522-
sf = soundfile.SoundFile(
2523-
file_path,
2524-
mode="w",
2525-
samplerate=96000,
2526-
channels=n_sig,
2527-
subtype=subtype,
2528-
format="FLAC",
2529-
)
2530-
with sf:
2531-
sf.write(d_signal)
2531+
if wfdb_archive:
2532+
with io.BytesIO() as f:
2533+
with soundfile.SoundFile(
2534+
f,
2535+
mode="w",
2536+
samplerate=96000,
2537+
channels=n_sig,
2538+
subtype=subtype,
2539+
format="FLAC", # required for file-like
2540+
) as sf:
2541+
sf.write(d_signal)
2542+
wfdb_archive.write(os.path.basename(file_name), f.getvalue())
2543+
return
2544+
else:
2545+
sf = soundfile.SoundFile(
2546+
file_path,
2547+
mode="w",
2548+
samplerate=96000,
2549+
channels=n_sig,
2550+
subtype=subtype,
2551+
format="FLAC",
2552+
)
2553+
with sf:
2554+
sf.write(d_signal)
25322555
return
25332556

25342557
else:
@@ -2549,8 +2572,13 @@ def wr_dat_file(
25492572
b_write = np.append(np.zeros(byte_offset, dtype="uint8"), b_write)
25502573

25512574
# Write the bytes to the file
2552-
with open(file_path, "wb") as f:
2553-
b_write.tofile(f)
2575+
if wfdb_archive:
2576+
with io.BytesIO() as f:
2577+
b_write.tofile(f)
2578+
wfdb_archive.write(os.path.basename(file_name), f.getvalue())
2579+
else:
2580+
with open(file_path, "wb") as f:
2581+
b_write.tofile(f)
25542582

25552583

25562584
def describe_list_indices(full_list):

wfdb/io/archive.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import shutil
23
import zipfile
34
from contextlib import contextmanager
45

@@ -60,6 +61,23 @@ def close(self):
6061
if self.zipfile:
6162
self.zipfile.close()
6263

64+
def write(self, filename, data):
65+
"""
66+
Write binary data to the archive (replaces if already exists).
67+
"""
68+
# Write to a new temporary archive
69+
tmp_path = self.archive_path + ".tmp"
70+
with zipfile.ZipFile(self.archive_path, mode="r") as zin:
71+
with zipfile.ZipFile(tmp_path, mode="w") as zout:
72+
for item in zin.infolist():
73+
if item.filename != filename:
74+
zout.writestr(item, zin.read(item.filename))
75+
zout.writestr(filename, data)
76+
77+
# Replace the original archive
78+
shutil.move(tmp_path, self.archive_path)
79+
self.zipfile = zipfile.ZipFile(self.archive_path, mode="a")
80+
6381
def create_archive(self, file_list, output_path=None):
6482
"""
6583
Create a .wfdb archive containing the specified list of files.

wfdb/io/record.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -905,7 +905,7 @@ def __eq__(self, other, verbose=False):
905905

906906
return True
907907

908-
def wrsamp(self, expanded=False, write_dir=""):
908+
def wrsamp(self, expanded=False, write_dir="", wfdb_archive=None):
909909
"""
910910
Write a WFDB header file and any associated dat files from this
911911
object.
@@ -939,7 +939,8 @@ def wrsamp(self, expanded=False, write_dir=""):
939939
if self.n_sig > 0:
940940
# Perform signal validity and cohesion checks, and write the
941941
# associated dat files.
942-
self.wr_dats(expanded=expanded, write_dir=write_dir)
942+
self.wr_dats(expanded=expanded, write_dir=write_dir,
943+
wfdb_archive=wfdb_archive)
943944

944945
def _arrange_fields(self, channels, sampfrom, smooth_frames):
945946
"""
@@ -2878,6 +2879,7 @@ def wrsamp(
28782879
base_date=None,
28792880
base_datetime=None,
28802881
write_dir="",
2882+
archive=False,
28812883
):
28822884
"""
28832885
Write a single segment WFDB record, creating a WFDB header file and any
@@ -2966,6 +2968,7 @@ def wrsamp(
29662968
# Check for valid record name
29672969
if "." in record_name:
29682970
raise Exception("Record name must not contain '.'")
2971+
29692972
# Check input field combinations
29702973
signal_list = [p_signal, d_signal, e_p_signal, e_d_signal]
29712974
signals_set = sum(1 for var in signal_list if var is not None)
@@ -3064,8 +3067,12 @@ def wrsamp(
30643067
else:
30653068
expanded = False
30663069

3070+
wfdb_archive = None
3071+
if archive:
3072+
wfdb_archive = get_archive(os.path.join(write_dir, record_name))
3073+
30673074
# Write the record files - header and associated dat
3068-
record.wrsamp(write_dir=write_dir, expanded=expanded)
3075+
record.wrsamp(write_dir=write_dir, expanded=expanded, wfdb_archive=wfdb_archive)
30693076

30703077

30713078
def dl_database(

0 commit comments

Comments
 (0)