Конвертировать xlxs в csv и формат данных - PullRequest
1 голос
/ 23 января 2020

У меня есть 2 проблемы при преобразовании файлов:

  1. Я бы хотел, чтобы формат даты выглядел так:
19.08.2019

и это выглядит так

8/19/2019

2.После преобразования дополнительные строки с запятыми добавляются в CSV-файл. Как я могу преодолеть это?

11,900011,S1,8/19/2019,11,6.90,9.90,,18.50,,8.80,,,,,,,,,,,,,,,,,,,,,,,,
12,900012,S1,8/19/2019,12,6.70,8.80,,14.50,,9.40,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
....

Я пользуюсь библиотекой

using Excel=Microsoft.Office.Interop.Excel;

Вот мой код:

 public static void Convert()
        {
            try
            {
                Excel.Application app = new Excel.Application();
                //Load file . xlsx
                Excel.Workbook wb = app.Workbooks.Open(Program.filePaths[1]);
                //Save file .csv
                wb.SaveAs(Program.filePaths[0], Excel.XlFileFormat.xlCSVWindows, Type.Missing, Type.Missing, false, false, Excel.XlSaveAsAccessMode.xlNoChange, Excel.XlSaveConflictResolution.xlLocalSessionChanges, false, Type.Missing, Type.Missing, Type.Missing);
                wb.Close(false);
                app.Quit();


            }catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }


        }

Заранее благодарю за помощь

Ответы [ 2 ]

0 голосов
/ 25 января 2020

Что касается даты, если ваша дата правильно отформатирована в Excel, Excel должен соблюдать этот формат при экспорте в CSV. Я предполагаю, что это не загромождает ваш существующий формат; это просто экспорт как есть, верно?

Excel.Worksheet sheet = wb.ActiveSheet;
sheet.Columns[4].NumberFormat = "yyyy.mm.dd";

Что касается дополнительных столбцов / строк ... это означает, что "что-то" находится в этих ячейках, даже если это просто форматирование. Если вы удалите столбец / строку, это предотвратит их экспорт при сохранении в формате CSV.

Если вы не знаете, что там, простой способ сделать это - найти последнюю строку с помощью " реальных данных, и это рассчитывает на то, что вы знаете, как определить это ... возможно, любую строку без содержимого в столбцах A, B и E. Возьмите строку после последней реальной строки и удалите все до последней строки UsedRange.

Кроме того, вы можете использовать встроенную функцию CountA в Excel, которая должна быть очень быстрой. Если функция возвращает 0 для строки, вы не можете рассчитывать на то, что она находится в любой ячейке этой строки. Быстрый пример:

Excel.Range last = sheet.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell,
    Type.Missing);

for (int row = last.Row; row > 0; row++)
{
    Excel.Range r = (Excel.Range)sheet.Cells[row, 1];
    double o = addIn.Application.WorksheetFunction.CountA(r.EntireRow);
    if (o == 0)
        r.EntireRow.Delete();
}

Непроверенный, но там должно быть 99% ... Я думаю, вам нужно go снизу вверх, но не уверен на 100%. Я думаю, это будет пропускать строки при удалении, если вы этого не сделаете.

0 голосов
/ 23 января 2020

Я конвертирую из Excel в CSV, используя npoi npoi (извините, из-за потери строк, это копия из моих проектов)

        public Dictionary<string, string> ExceltoCsv(IWorkbook input)
    {
        var csvTrennzeichen = OutputSettings.ColumnSeparator.ToString();
        var result = new Dictionary<string, string>();
        for (var sheetIndex = 0; sheetIndex < input.NumberOfSheets; sheetIndex++)
        {
            var sheet = input.GetSheetAt(sheetIndex);
            var sheetresult = new List<string>();
            for (var row = sheet.FirstRowNum; row < sheet.LastRowNum; row++)
            {
                var rowObj = sheet.GetRow(row);
                if (rowObj.Cells.All(x => string.IsNullOrEmpty(WertAuslesen(x))))
                    continue;

                var line = string.Join(csvTrennzeichen, rowObj.Cells
                                                        .Select(cell => WertAuslesen(cell).Replace("\r", " ").Replace("\n", " "))
                                                        .Select(cell => OutputSettings.Writeinquotes ? string.Format("\"{0}\"", cell.Replace("\"", "\"\"")) : cell));

                sheetresult.Add(line);
            }

            result.Add(sheet.SheetName, string.Join("\r\n", sheetresult));
        }
        return result;
    }

    private string WertAuslesen(ICell oldCell)
    {
        switch (oldCell.CellType)
        {
            case CellType.Boolean:
                return oldCell.BooleanCellValue.ToString();
            case CellType.Error:
                return oldCell.ErrorCellValue.ToString();
            case CellType.Formula:
                return oldCell.CellFormula;
            case CellType.Numeric:
                return !DateUtil.IsCellDateFormatted(oldCell)
                    ? oldCell.NumericCellValue.ToString(OutputSettings.GetDecimalFormat(Digits(oldCell.CellStyle.GetDataFormatString())))
                    : oldCell.DateCellValue.ToString(OutputSettings.DateFormat);
            case CellType.String:
                return oldCell.RichStringCellValue.ToString();
            case CellType.Unknown:
                return oldCell.StringCellValue;
            default:
                return "";
        }
    }

    private static int Digits(string format)
    {
        var digits = format.ContainsAny(',', '.') ? format.Split(new[] { ',', '.' }).Last() : "";
        return digits.Length;
    }

я также чувствую необходимость добавить Класс outputsettings, так как он очищает вещи, его не нужно, но

    public class OutputSettings
{
    public static readonly OutputSettings Default = new OutputSettings(Encoding.UTF8, null, "yyyyMMdd", "hh:mm:ss", ".", "", "y", "n", ',', true, "", null);
    //I am immutable
    public OutputSettings(CultureInfo culture) : this(
        Encoding.UTF8,
        null,
        culture.DateTimeFormat.ShortDatePattern,
        culture.DateTimeFormat.LongTimePattern,
        culture.NumberFormat.NumberDecimalSeparator,
        culture.NumberFormat.NumberGroupSeparator,
        "y",
        "n",
        ',',
        true,
        "",
        null)
    {
    }

    public OutputSettings(
        Encoding encoding,
        Version ioVersion,
        string dateFormat,
        string timeFormat,
        string decimalSeperator,
        string thousandSeperator,
        string yesString,
        string noString,
        char columnseperator,
        bool writeinquotes,
        string outputFolder,
        IResourceHandler resourceHandler)
    {
        Encoding = encoding;
        IOVersion = ioVersion;
        DateFormat = dateFormat;
        TimeFormat = timeFormat;
        DecimalSeperator = decimalSeperator;
        ThousandSeperator = thousandSeperator;
        YesString = yesString;
        NoString = noString;
        ColumnSeparator = columnseperator;
        Writeinquotes = writeinquotes;
        OutputFolder = outputFolder;
        ResourceHandler = resourceHandler;
    }

    public IResourceHandler ResourceHandler { get; }

    public Encoding Encoding { get; }

    public Version IOVersion { get; }

    public string DateFormat { get; }

    public string TimeFormat { get; }

    public string DateTimeFormat => DateFormat + " " + TimeFormat;

    public string DecimalSeperator { get; }

    public string ThousandSeperator { get; }

    public string DecimalFormat => GetDecimalFormat(2);

    public string YesString { get; }

    public string NoString { get; }

    private char _columnseperator;
    public char ColumnSeparator
    {
        get
        {
            return _columnseperator;
        }
        private set
        {
            if (value != ',' && value != ';')
                throw new ArgumentException(Localization.Resources.StaticTranslationResource.IO_SEPARATOR_MUSS_COMMA_ODER_SEMICOLON_SEIN);
            _columnseperator = value;
        }
    }

    public bool Writeinquotes { get; }
    public string OutputFolder { get; set; }

    public string GetDecimalFormat(int precision)
    {
        if (precision < 0)
            throw new ArgumentException(Localization.Resources.StaticTranslationResource.OUTPUT_ANZAHL_DER_STELLEN_DARF_NICHT_NEGATIV_SEIN, nameof(precision));

        var sb = new StringBuilder($"#{ThousandSeperator}##0{DecimalSeperator}");
        if (precision == 0)
        {
            sb.Append('#');
        }
        else
        {
            for (int i = 0; i < precision; i++)
            {
                sb.Append('0');
            }
        }
        return sb.ToString();
    }
}

edit: я использую множество методов расширения, чтобы сделать мой код легко читаемым, содержит один из них

        public static bool ContainsAll<T>(this IEnumerable<T> superset, params T[] subset) => !subset.Except(superset).Any();

    public static bool ContainsAll<T>(this IEnumerable<T> superset, IEnumerable<T> subset) => !subset.Except(superset).Any();

    public static bool ContainsAny<T>(this IEnumerable<T> superset, params T[] subset) => subset.Any(superset.Contains);

    public static bool ContainsAny<T>(this IEnumerable<T> superset, IEnumerable<T> subset) => subset.Any(superset.Contains);
...