/// <summary> /// Appends a set of traces to the end of the file or trace series. /// </summary> /// <param name="traces">Traces to write</param> /// <param name="progress">A progress handler</param> /// <param name="ct">Cancellation token</param> public void Write(IEnumerable <SegyTrace> traces, IProgress <int> progress = null, CancellationToken ct = default(CancellationToken)) { CodeContract.Requires <NullReferenceException>(traces != null, "Traces cannot be null."); if (ct.IsCancellationRequested) { return; } BigArray <SegyTrace> segyTraces = traces as BigArray <SegyTrace> ?? traces.ToBigArray(); CodeContract.Assume(segyTraces.Any(), "There must be at least one trace to write."); // get "traces" statistics. var distinctTraceSampleCounts = traces.Select(tr => tr.Data.Length).Distinct(); int numTraceLengths = distinctTraceSampleCounts.Count(); // assume number of trace lengths is 1. CodeContract.Assume(numTraceLengths == 1, "There are traces to write with inconsistent lengths. All traces must have the same length"); _stream.Seek(0, SeekOrigin.End); if (TraceSampleCount == 0) { TraceSampleCount = distinctTraceSampleCounts.FirstOrDefault(); } else { CodeContract.Assume(TraceSampleCount == distinctTraceSampleCounts.FirstOrDefault(), "Trace lengths to write is not consistent with the rest of the trace lengths in this file."); } var currProgress = 0; long traceCount = segyTraces.LongCount(); long ctr = 0; foreach (var sgyTrace in traces) { _writer.Write(sgyTrace.GetBytes()); ctr++; // report progress and cancel if requested if (ct.IsCancellationRequested) { break; } if (progress == null) { continue; } var progPercent = (int)(100 * (double)ctr / traceCount); if (currProgress == progPercent) { continue; } progress?.Report(progPercent); currProgress++; } }