private void WriteDataCore(IChannel ch, TextWriter writer, IDataView data, out string argsLoader, out long count, out int min, out int max, params int[] cols) { _host.AssertValue(ch); ch.AssertValue(writer); ch.AssertValue(data); ch.AssertNonEmpty(cols); // Determine the active columns and whether there is header information. bool[] active = new bool[data.Schema.ColumnCount]; for (int i = 0; i < cols.Length; i++) { ch.Check(0 <= cols[i] && cols[i] < active.Length); ch.Check(data.Schema.GetColumnType(cols[i]).ItemType.RawKind != 0); active[cols[i]] = true; } bool hasHeader = false; if (_outputHeader) { for (int i = 0; i < cols.Length; i++) { if (hasHeader) { continue; } var type = data.Schema.GetColumnType(cols[i]); if (!type.IsVector) { hasHeader = true; continue; } if (!type.IsKnownSizeVector) { continue; } var typeNames = data.Schema.GetMetadataTypeOrNull(MetadataUtils.Kinds.SlotNames, cols[i]); if (typeNames != null && typeNames.VectorSize == type.VectorSize && typeNames.ItemType.IsText) { hasHeader = true; } } } using (var cursor = data.GetRowCursor(i => active[i])) { var pipes = new ValueWriter[cols.Length]; for (int i = 0; i < cols.Length; i++) { pipes[i] = ValueWriter.Create(cursor, cols[i], _sepChar); } // REVIEW: This should be outside the cursor creation. string header = CreateLoaderArguments(data.Schema, pipes, hasHeader, ch); argsLoader = header; if (_outputSchema) { WriteSchemaAsComment(writer, header); } double rowCount = data.GetRowCount(true) ?? double.NaN; using (var pch = !_silent ? _host.StartProgressChannel("TextSaver: saving data") : null) { long stateCount = 0; var state = new State(this, writer, pipes, hasHeader); if (pch != null) { pch.SetHeader(new ProgressHeader(new[] { "rows" }), e => e.SetProgress(0, stateCount, rowCount)); } state.Run(cursor, ref stateCount, out min, out max); count = stateCount; if (pch != null) { pch.Checkpoint(stateCount); } } } }