Текстовый файл в Excel - PullRequest
       52

Текстовый файл в Excel

0 голосов
/ 13 февраля 2019

У меня есть текстовый файл, содержащий содержимое таблицы, например:

 |ID    |SN| | Date | Code |Comp|Source|        Format          |Unit|BuyQTY|DoneQTY|YetQTY|Late

 21C011  5   1080201 BAO-99 高雄  10P056 5X3X5M/R   RBDC-18865LA M    10000    7000    3000   1                                                                                                                                
 21C006  1   1080201 BAO-99 高雄  20A001 5X8X2M/R 高廠軟 Q 料     M    60000   40000   20000   1   
 21C002  6   1080201 BAO-99 高雄  10W013 5X1X5M/R PVC+UV         M   202000  100500  101500      
 21C006  4   1080212 BAO-99 高雄  10P038 4X5X5M/R    DIGI PACK    M   255000          255000      
 21C006  5   1080212 BAO-99 高雄  10P039 4X6X5M/R    DIGI PACK         295000          295000      
 21C006  6   1080212 BAO-99 高雄  10P040 4X2X5M/R    DIGI PACK    M   114000          114000      
 21C006  7   1080212 BAO-99 高雄  10P041 4X9X5M/R    DIGI PACK    M    49500           49500

Обратите внимание, что в столбце "Формат" много пропущенных значений и различной длины.

Я пытался прочитать его в Excel, например:

Excel Result

Из-за пропущенных значений и разной длины формата я НЕ могу просто использоватьSplit.

Я пытался использовать Graphics.MeasureString(), чтобы получить ширину подстроки между определенными длинами.

Например, ширина между 125 и 140 будет "Единицей".

Но из-за китайских иероглифов и пробелов результат все "криво"!

Я никогда не смогу получить его в нужную колонку!

Может кто-нибудь быть таким добрым и научитьмне, как я могу сделать это правильно!?

Очень ценю !!!

Обновление:

Потому что я пишу программу для кто-нибудь сделает такую ​​задачу, поэтому я НЕ МОГУ попросить его изменить исходный текст через NotePad ++ or Любое другое программное обеспечение.

Я также могу НЕ попросить его импортировать его с помощью Excel и установить ширину столбцов!

ВСЕ, потому что это для их удобства !!!

Поэтому я извиняюсь ОЧЕНЬ ОЧЕНЬ, если не смогу облегчить жизнь !!!

PS.Китайские символы: BIG5.

Ниже приведен код, который я использую для анализа текстового файла в DataGridView:

float[] colLens = new float[] { 137, 161, 301, 359, 400, 510, 760, 804, 872, 944, 1010, 1035,1050 };
Graphics g = CreateGraphics();

str = File.ReadAllLines(ofd.FileName,Encoding.GetEncoding("BIG5"));
for(int i = 0; i < str.Count(); i++)
{
    int c = 0;
    DataGridViewRow row = new DataGridViewRow();

    row.CreateCells(dgvMain);
    d = -1;
    for(int j = 1; j < str[i].Length ; j++)
    {
        string s = str[i].Substring(0,  j);
        SizeF size = g.MeasureString(s, new Font("細明體", 12));

        for (int k = d + 1; k < colLens.Count()-1; k++)
        {
            if (size.Width < colLens[k]) break;
            else if(size.Width < colLens[k + 1])
            {
                d = k;
                row.Cells[d].Value = str[i].Substring(c, j - c);
                c = j;
                break;
            }
        }
    }
    dgvMain.Rows.Add(row);
}

Ответы [ 3 ]

0 голосов
/ 13 февраля 2019

Китайские кодировки имеют переменную длину, будь то Big5 или GB18030.Это означает, что X хранится как один байт, а хранится как два байта.Кажется, этот файл имеет фиксированную длину байт на поле, а не фиксированную длину символа.

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

В худшем случае вы можете читать байты непосредственно из файлового потока.Каждый набор байтов можно преобразовать в строку, используя Encoding.ToString.Вы можете получить кодировку Big5 с помощью Encoding.GetEncoding(950).

Encoding _big5=Encoding.GetEncoding(950);
byte[] _buffer=new byte[90];


public string GetField(FileStream stream,int offset, int length)
{
    var read=stream.ReadBytes(_buffer,offset,length);
    if(read>0)
    {
        return _big5.GetString(buffer,0,read);
    }
    else 
    {
        return "";
    }
}

//Quick & dirty way to skip to end
public void SkipToLineEnd(FileStream stream)
{
    int c;
    while((in=stream.ReadByte()>-1)
    {
        if (c==(int)'\n')
        {
            return;
        }
    }
}

. Вы можете построить запись из строки следующим образом:

public MyRecord GetNextRecord(FileStream stream)
{
    var record = new MyRecord 
                 {
                     Id=GetField(stream,0,9),
                     ...
                     //6 bytes, not just 4
                     Comp = GetField(stream,28,6),
                     ..
                     //Start from 50, 16 bytes
                     Format =  GetField(stream,50,16)
                 };
        SkipToLineEnd(stream);
        return myRecord;        
}

Вы можете написать метод итератора, который читает записи этогопуть, пока он не достигнет конца файла.Быстрый и грязный способ сделать это - проверить, находится ли Position потока настолько близко к концу, что не может быть получена полная запись, например:

public IEnumerable<MyRecord> GetRecords(FileStream stream,int recordLength)
{
    while(stream.Position < stream.Length - recordLength)
    {
        yield return GetRecordNextRecord(stream);
    }
}

И используйте его следующим образом:

var records=GetRecords(myStream,96);
foreach(var record in records)
{
    ....
}

Это позаботится о том, чтобы завершать новые строки и, возможно, прерывать последние строки.

Чтобы пропустить строки заголовка, просто позвоните SkipToLineEnd() столько раз, сколько необходимо.

Вы можете использовать такую ​​библиотеку, как EPPlus , чтобы сгенерировать файл Excel непосредственно из этогонапример,

using (var p = new ExcelPackage())
{
    var ws=p.Workbook.Worksheets.Add("MySheet");
    ws.Cells.LoadFromCollection(records);
    p.SaveAs(new FileInfo(@"c:\workbooks\myworkbook.xlsx"));
}
0 голосов
/ 13 февраля 2019

Эта задача не так проста, как кажется.Код работает с размещенным вводом.Это может потребовать небольшой корректировки.Смотрите код ниже

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Data;

namespace ConsoleApplication100
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.csv";
        static void Main(string[] args)
        {
            //|ID    |SN| | Date | Code |Comp|Source|        Format          |Unit|BuyQTY|DoneQTY|YetQTY|Late
            DataTable dt = new DataTable();
            dt.Columns.Add("ID", typeof(string));
            dt.Columns.Add("SN", typeof(string));
            dt.Columns.Add("Date", typeof(string));
            dt.Columns.Add("Code", typeof(string));
            dt.Columns.Add("Comp", typeof(string));
            dt.Columns.Add("Source", typeof(string));
            dt.Columns.Add("Format", typeof(string));
            dt.Columns.Add("Unit", typeof(string));
            dt.Columns.Add("BuyQTY", typeof(int));
            dt.Columns.Add("DoneQTY", typeof(int));
            dt.Columns.Add("YetQTY", typeof(int));
            dt.Columns.Add("Late", typeof(int));

            StreamReader reader = new StreamReader(FILENAME, Encoding.Unicode);

            string line = "";
            int lineCount = 0;
            while((line = reader.ReadLine()) != null)
            {
                if ((++lineCount > 1) && (line.Trim().Length > 0))
                {
                    string leader = line.Substring(0, 30).Trim();
                    string source = line.Substring(31, 16).Trim();

                    string trailer = line.Substring(48).TrimStart();
                    string format = trailer.Substring(0, 12).TrimStart();
                    trailer = trailer.Substring(12).Trim();

                    DataRow newRow = dt.Rows.Add();

                    string[] splitLeader = leader.Split(new char[] {' '}, StringSplitOptions.RemoveEmptyEntries);
                    newRow["ID"] = splitLeader[0].Trim();
                    newRow["SN"] = splitLeader[1].Trim();
                    newRow["Date"] = splitLeader[2].Trim();
                    newRow["Code"] = splitLeader[3].Trim();
                    newRow["Comp"] = splitLeader[4].Trim();
                    newRow["Source"] = source;
                    newRow["Format"] = format;


                    newRow["Unit"] = trailer.Substring(0,4).Trim();
                    newRow["BuyQTY"] = int.Parse(trailer.Substring(4, 8));

                    string doneQTYstr = trailer.Substring(12, 8).Trim();
                    if (doneQTYstr.Length > 0)
                    {
                        newRow["DoneQTY"] = int.Parse(doneQTYstr);
                    }

                    if (trailer.Length <= 28)
                    {
                        newRow["YetQTY"] = int.Parse(trailer.Substring(20));
                    }
                    else
                    {
                        newRow["YetQTY"] = int.Parse(trailer.Substring(20,8));
                        newRow["late"] = int.Parse(trailer.Substring(28));
                    }

                }
            }

        }
    }
}
0 голосов
/ 13 февраля 2019

Мои два цента: сначала используйте «Split» и читайте от источника до столбца источника, затем с конца до единицы (обратите внимание на «обратный» порядок).То, что осталось, это формат.

То есть, если использование фиксированных столбцов и ТОЛЬКО форматирование создает проблемы,

var colsIdToSource = line.left(200); //Assuming 200 is the sum of cols up to source
var colsUnitToLate = line.right(150); //idem from unit to late
var formatColumn = line.substring(200, line.length-150); // May need to adjust a char or less

Затем вы обрабатываете известные столбцы.

Удачи:)

...