C #, чтение в записях с фиксированной шириной, различные типы записей в одном файле - PullRequest
3 голосов
/ 03 июля 2010

Для начала хотелось бы уточнить, что я не очень хорошо разбираюсь в C #.В этом проекте, который я выполняю в C # с использованием .Net 3.5, я создаю класс для чтения и экспорта файлов, которые содержат несколько форматов фиксированной ширины на основе типа записи.

В настоящее время существует 5 типовзаписей, обозначенных первой символьной позицией в каждой строке файла, которые указывают конкретный формат строки.У меня проблема в том, что типы отличаются друг от друга.

Record type 1 has 5 columns, signifies beginning of the file

Record type 3 has 10 columns, signifies beginning of a batch
Record type 5 has 69 columns, signifies a transaction
Record type 7 has 12 columns, signifies end of the batch, summarizes
(these 3 repeat throughout the file to contain each batch)

Record type 9 has 8 columns, signifies end of the file, summarizes

Есть ли хорошая библиотека для таких файлов фиксированной ширины?Я видел несколько хороших, которые хотят загрузить весь файл как одну спецификацию, но это не сработает.

Примерно 250 из этих файлов читаются в конце каждого месяца и в среднем объединяют размер файласоставляет около 300 мегабайт.Эффективность очень важна для меня в этом проекте.

Основываясь на своих знаниях данных, я построил иерархию классов того, что, по моему мнению, должен выглядеть объект ...

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

namespace Extract_Processing
{
    class Extract
    {
        private string mFilePath;
        private string mFileName;
        private FileHeader mFileHeader;
        private FileTrailer mFileTrailer;
        private List<Batch> mBatches;       // A file can have many batches

        public Extract(string filePath)
        { /* Using file path some static method from another class would be called to parse in the file somehow */ }

        public string ToString()
        { /* Iterates all objects down the heiarchy to return the file in string format */ }

        public void ToFile()
        { /* Calls some method in the file parse static class to export the file back to storage somewhere */ }
    }

    class FileHeader
    { /* ... contains data types for all fields in this format, ToString etc */ }

    class Batch
    {
        private string mBatchNumber;                // Should this be pulled out of the batch header to make LINQ querying simpler for this data set?
        private BatchHeader mBatchHeader;
        private BatchTrailer mBatchTrailer;
        private List<Transaction> mTransactions;    // A batch can have multiple transactions

        public string ToString()
        { /* Iterates through batches to return what the entire batch would look like in string format */ }
    }

    class BatchHeader
    { /* ... contains data types for all fields in this format, ToString etc */ }

    class Transaction
    { /* ... contains data types for all fields in this format, ToString etc */ }

    class BatchTrailer
    { /* ... contains data types for all fields in this format, ToString etc */ }

    class FileTrailer
    { /* ... contains data types for all fields in this format, ToString etc */ }

}

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

Самый большой вопрос, помимо некоторой критики, как я должен внести этофайл?Я ввел много файлов на других языках, таких как VBA, используя методы FSO, Microsoft Access ImportSpec для чтения в файле (5 раз, по одному на каждую спецификацию ... вау, который был неэффективен!), Создал объект «Курсор» вVisual FoxPro (который был FAAAAAAAST, но опять же, должен был сделать пять раз), но я ищу скрытые драгоценные камни в C #, если указанные вещи существуют.

Спасибо за чтение моего романа, дайте мне знать, если у вас возникли проблемы с его пониманием.Я беру выходные, чтобы изучить этот дизайн и посмотреть, куплю ли я его и хочу ли он реализовать его таким образом.

Ответы [ 4 ]

4 голосов
/ 03 июля 2010

FileHelpers это хорошо.У него есть несколько недостатков, заключающихся в том, что он, похоже, больше не находится в активной разработке, и он заставляет вас использовать публичные переменные для ваших полей вместо того, чтобы позволять вам использовать свойства.Но в остальном хорошо.

Что вы делаете с этими файлами?Вы загружаете их в SQL Server?Если это так, и вы ищете БЫСТРЫЙ и ПРОСТОЙ, я бы порекомендовал такой дизайн:

  1. Создайте промежуточные таблицы в вашей базе данных, которые соответствуют каждому из 5 типов записей.Попробуйте также добавить столбец LineNumber и столбец FileName, чтобы можно было отслеживать проблемы обратно в сам файл.
  2. Считывайте файл построчно и анализируйте его в своих бизнес-объектах или непосредственно в ADO.NET DataTable.объекты, которые соответствуют вашим таблицам.
  3. Если вы использовали бизнес-объекты, примените преобразования данных или бизнес-правила, а затем поместите данные в объекты DataTable, которые соответствуют вашим таблицам.
  4. Как только каждый объект DataTable достигнетсоответствующий BatchSize (скажем, 1000 записей), используйте объект SqlBulkCopy для закачки данных в ваши промежуточные таблицы.После каждой операции SqlBulkCopy очищайте DataTable и продолжайте обработку.
  5. Если вы не хотите использовать бизнес-объекты, выполните какие-либо окончательные манипуляции с данными в SQL Server.

Вы можетевероятно, выполнить все это в менее чем 500 строк C #.

2 голосов
/ 03 июля 2010

Самый большой вопрос, помимо некоторой критики, как мне внести этот файл?

Я не знаю ни одной хорошей библиотеки для ввода / вывода файлов, но чтение довольно простое.

Создание класса StreamReader с использованием буфера 64 КБ для ограничения операций дискового ввода-вывода (по моим оценкам, в среднем 1500 транзакций на файл на конец месяца).

Теперь вы можетепоток через файл:1) Использование Read в начале каждой строки для определения типа записи.2) Использование метода ReadLine с методом String.Split для получения значений столбцов.3) Создайте объект, используя значения столбцов.

или

Вы можете просто буферизовать данные из потока вручную и IndexOf + SubString для повышения производительности (если все сделано правильно).

Также, если строки были не столбцами, а примитивными типами данных в двоичном формате, вы могли бы использовать класс BinaryReader для очень простого и производительного способа чтения объектов.

1 голос
/ 03 июля 2010

У меня есть одна критика: вы неправильно используете ToString.

    public string ToString()

Должно быть:

    public override string ToString()
0 голосов
/ 03 июля 2010

Лучшая библиотека для таких вещей - filehelpers

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...