C#, чтение записей фиксированной ширины, различные типы записей в одном файле

Для начала я хотел бы уточнить, что я не очень хорошо разбираюсь в 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 #, если такие вещи существуют.

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


person Mohgeroth    schedule 03.07.2010    source источник
comment
время выполнения является наивысшим приоритетом. А как насчет ремонтопригодности, удобочитаемости, правильности и т. д. Они менее важны, чем время выполнения?   -  person Mark Byers    schedule 03.07.2010
comment
Ну, не для того, чтобы вязать, весь процесс, очевидно, имеет высокий приоритет ... если он сломается, я буду работать над этим на выходных, а не отдыхать. Однако процессы, которые использовались до сих пор, являются довольно медленными реализациями доступа ms, и их попросили найти способ сделать это таким образом, чтобы он был не только быстрее, но и имел возможность выплевывать файлы обратно для модификации.   -  person Mohgeroth    schedule 03.07.2010


Ответы (3)


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

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

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

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

or

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

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

person Jaroslav Jandek    schedule 03.07.2010
comment
Лучшая производительность и меньше головной боли с помощью MultiRecordEngine файловых помощников для того, что я пытаюсь сделать. Не тот подход, на который я бы надеялся, но он достаточно эффективен - person Mohgeroth; 10.07.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#.

person mattmc3    schedule 03.07.2010
comment
Я определенно не хочу размещать это на SQL-сервере, поскольку размер одних только исходных файлов извлечения за один год превышает 3 гигабайта! Эти файлы служат нашей резервной копией, и нам нужны определенные вещи как для выставления счетов, так и для ведения учета клиентов, но реальность такова, что если кто-то хочет что-то узнать о клиенте X в определенный момент времени, мы можем просто разархивировать файлы (коэффициент сжатия 98%). и просто используйте процесс, чтобы прочитать и извлечь то, что клиент хочет знать. Быстрое чтение этих данных помогает, поэтому мы можем позже создать приятный интерфейс для детализации данных. Но информация отличная, спасибо! - person Mohgeroth; 03.07.2010
comment
Пфф... 3 Гб!? Это ничего! Я думаю, что хранение данных так долго меня утомляло :) - person mattmc3; 23.06.2011

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

    public string ToString()

Должно быть:

    public override string ToString()
person Mark Byers    schedule 03.07.2010