본문 바로가기

C#/예제 코드

c# DataTable 컬럼정보 이쁘게 출력하기 (콘솔)

사전지식

DataTable의 칼럼 정보를 전체적으로 망라할 수 있는 소스를 뒤져봤지만, 전각 문자에 대한 지원이 미흡하다던가.. 대충 텍스트만 출력한다든가.. 맘에 드는 것이 없어서 직접 소스를 작성하였다.

 


준비물

.net6.0 이상의 버전

에디터는 vscode or vs2022을 추천.


실습

1. 메서드 작성.

using System.Data;
internal static class DataTableEX
{
    public static void PrintColumns(this DataTable table)
    {
        DataColumn[] columns = table.Columns.Cast<DataColumn>().ToArray();
        if (columns.Length == 0)
        {
            Console.WriteLine("NO columns");
            return;
        }


        int RealLen(string str) => str.Select(x => (0xFF00 & x) == 0 ? 1 : 2).Sum();
        int UnRealLen(string str) => str.Select(x => (0xFF00 & x) == 0 ? 0 : 1).Sum();
        string GetDataMemberType(DataColumn column)
        {
            var rt = column.DataType.ToString();
            if (column.DataType.Namespace == "System")
            {
                rt = rt.Substring(column.DataType.Namespace.Length + 1);
            }
            return rt + (column.AllowDBNull ? "?" : "");
        }



        var colNames = new[] { " №", "Column Name", "Data Type", "Nullable" };

        var colsLen = new[] {
                columns.Select(c => c.Ordinal).Max().ToString().Length,
                columns.Select(c => RealLen(c.ColumnName)).Max(),
                columns.Select(c => GetDataMemberType(c).Length).Max(),
                colNames[3].Length,
            }.Select((x, i) => Math.Max(colNames[i].Length, x)).ToArray();


        var align = new[] { 1, -1, -1, -1 }.Select((num, i) =>
                               new Func<string, string>(str =>
                               String.Format($"{{0,{num * (colsLen[i] - UnRealLen(str))}}}", str))).ToArray();


        var pk = columns[0].Table.PrimaryKey;

        var fks = from co in columns[0].Table.Constraints.Cast<Constraint>()
                  where co is ForeignKeyConstraint
                  select co as ForeignKeyConstraint;

        var keys = from o in
                       from c in columns
                       select (c, keys: new Dictionary<string, bool>()
                       {
                           ["pk"] = pk.Contains(c),
                           ["uk"] = c.Unique,
                           ["ro"] = c.ReadOnly
                       })
                   where o.keys.Any(x => x.Value)
                   orderby o.keys.Values.Select((x, i) => (x ? int.MinValue : 0) >> i + 1).Sum() +
                           o.c.Ordinal
                   select o.c.ColumnName +
                          $"({String.Join(",", o.keys.Where(x => x.Value).Select(x => x.Key))})";


        string PadBoth(string source, int length)
        {
            int spaces = length - RealLen(source);
            return new String(' ', spaces / 2) + source + new string(' ', spaces - spaces / 2);
        }

        var preBg = Console.BackgroundColor;
        Console.BackgroundColor = ConsoleColor.DarkCyan;
        Console.WriteLine(PadBoth(table.TableName, (colsLen.Sum() + 14)));
        Console.BackgroundColor = preBg;

        if (keys.Count() > 0) Console.WriteLine(string.Join(", ", keys));
        if (fks.Count() > 0)
        {
            var str = string.Join("\n", fks.Select(x => x.ConstraintName + ":(" +
                      string.Join(",", x.Columns.Select(x => x.ColumnName)) + ") -> " +
                      x.RelatedColumns[0].Table.TableName + "(" +
                      string.Join(",", x.RelatedColumns.Select(x => x.ColumnName)) + ")"));
            Console.WriteLine(str);
        }


        Console.WriteLine($"┌{  String.Join('┬', colsLen.Select(x => new String('-', x + 2)))        }┐");
        Console.WriteLine($"│{ String.Join(" │ ", colNames.Select((x, i) => x.PadRight(colsLen[i])))} │");
        Console.WriteLine($"├{  String.Join('┼', colsLen.Select(x => new String('-', x + 2)))        }┤");

        foreach (DataColumn column in columns)
        {
            var colsAttr = new object[] {
                    column.Ordinal,
                    column.ColumnName,
                    GetDataMemberType(column),
                    column.AllowDBNull,
                };
            Console.WriteLine($"│ {String.Join(" │ ", colsAttr.Select((x, i) => align[i](x.ToString())))} │");
        }

        Console.WriteLine($"└{ String.Join('┴', colsLen.Select(x => new String('-', x + 2)))     }┘");
        Console.WriteLine();
    }
}

2. 테스트 소스 작성.

※ .net6.0 ( C#10.0 에서는 Main()을 생략한다 )

using System.Data;

 

Console.OutputEncoding = System.Text.Encoding.UTF8;

 

var dt = new DataTable("Hello Table");
dt.Columns.Add("string", typeof(string)).AllowDBNull = false;
dt.Columns.Add("string2", typeof(string)).AllowDBNull = false;
dt.Columns.Add("int", typeof(int)).Unique = true;
dt.Columns.Add("double", typeof(double)).ReadOnly = true;
dt.Columns.Add("decimal", typeof(decimal)).Unique = true;
dt.Columns.Add("DateTime", typeof(DateTime)).Unique = true;
dt.Columns.Add("가나다라마바사앙앙!");
dt.Columns.Add("んん,気持ちぃ♡");
dt.Columns.Add("吃饭了吗?");
dt.Columns.Add("吃飯了嗎?");
dt.Columns.Add("Ты съел?");

 

dt.PrimaryKey = new[] { dt.Columns["int"], dt.Columns["double"] };

 

var dt2 = new DataTable("TARGET");

 

var foreignKey = new ForeignKeyConstraint("SUB_FK",
    new[] { dt2.Columns.Add("COL_0"), dt2.Columns.Add("COL_1") },
    new[] { dt.Columns["string"], dt.Columns["string2"] });

 

foreignKey.DeleteRule = Rule.SetDefault;

 

dt.Constraints.Add(foreignKey);

 

dt.PrintColumns();


주의사항 및 후기

콘솔 창의 폰트는 돋움체나 굴림체 같은 체(體)로 끝나는.. 크기가 고정적인 폰트를 사용해야 포맷이 깨지지 않는다.

vscode는 기본 폰트가 고정적이 아니므로 설정> 기능> 디버그> Font Family 에서 GulimChe로 바꾸는 것을 추천한다.

그리고 특정 외국 글자는 표현이 안되거나 포맷이 깨진다. 

전각과 반각의 규칙을 1바이트 초과 유무로 구분 지었는데, 그 예상을 뛰 넘는 글자가 있다 (예:태국어)

 

Console.OutputEncoding = System.Text.Encoding.UTF8  이 구문을 빼면 특정 문자가 깨진다.

콘솔 창은 기본적으로 UTF8이 아니기 때문이다.

 

UTF8로 바꾸는 다른 방법들 :

2021.12.30 - [C#] - 콘솔창 UTF 8 로 바꾸기 (win 10에서 4가지 방법)

 

좀 더 정확한 반각문자를 알고 싶다면:

2021.12.31 - [C#/예제 코드] - c# 전각 or 반각 문자 전부 찾기 (콘솔)

 

c#으로 폰트(글꼴)을 바꾸고 싶다면:

2022.01.01 - [C#/예제 코드] - c# 콘솔 폰트 확인 및 폰트(글꼴,크기) 변경

 

👩자매품👧 데이터 출력:

2022.01.02 - [C#/예제 코드] - c# DataTable 데이터 이쁘게 출력하기 (콘솔)

 

 

출처 https://self-edu.tistory.com/