Delphi-Help

Главная

Использование текстовых файлов для импорта и экспорта

Оцените материал
(0 голосов)


Использование текстовых файлов для импорта и экспорта

Текстовые файлы являются универсальным средство импорта/экспорта, например, в Экселе может очень легко импортировать текстовые файлы, в одном из распознаваемых им форматов. Допустимы следующие форматы:

· Comma Separated Value (CSV), данные разделенные запятой;

· Tab Delimited (TXT), данные разделенные символом табуляции, легко распознается Экселем;

· Symbol Delimited (TXT), данные разделенные указанным определенным символом, частный случай это Tab delimited, но его достоинство состоит в том, что в Экселе можно определить множество символов разделения, например одновременно разделителями могут быть ЗАПЯТАЯ, ТАБЛУЛЯЦИЯ и ТОЧКА С ЗАПЯТОЙ, Эксель разделит правильно;

· Fixed (TXT), данные имеют фиксированную длину колонок.

Все четыре формата имеют свое назначение, по умолчанию CSV формат считается универсальным форматом, поскольку многие программы и даже некоторые языки программирования поддерживают его. Недостатком является некоторая избыточность. Самые экономные - это Tab delimited и Symbol Delimited, поскольку для разделение используется только один символ. Самый не экономный формат Fixed, поскольку для размещения данных всегда используется полная длина, его достоинством является простота обработки файла, можно просто читать фиксированными порциями или даже определить структуру в программе. Многие программы пишут свои логи именно в этом формате.

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

Пример 1, экспорт в файл в формате Comma Separated Value

Основой для экспорта в CSV является понимание некоторых вещей:

1. Первая строка должна быть строкой заголовков колонок;

2. Данные разделяются запятой;

3. Числовые данные пишутся, как есть;

4. Строковые данные заключаются в двойные кавычки;

5. Даты распознаются если они в формате MM/DD/YYYY, заключать в кавычки не надо;

6. Расширение файла должно быть CSV.

Будьте осторожнее, обратный экспорт из Экселя работает не так как ожидается, формат далек от CSV, для обратного экспорта правильнее использовать формат Tab Delimited, с ним не ожидается таких сложностей и странностей. Есть еще странности, например, очень отличаются по действию открытие этих файлов из меню и открытие по ассоциации с расширением. Результаты очень удивят. Попробуйте поэкспериментировать с файлами и с Экселем, только сохраняйте в файлы с различными именами. При открытии по ассоциации (двойной щелчок) и расширении CSV получается полностью автоматический импорт.

Умолчания для примера:

1. StringGrid создан и содержит некоторое количество колонок и строк, количество определяется при экспорте;

2. Информация о типах данных в колонках StringGrid, то будем считать, что первая колонка целое число, вторая это дата в региональном формате и третья колонка это текст, больше колонок у нас нет.

3. Количество строк зависит от наполнения.

4. Нулевая строка как обычно содержит заголовки колонок.

5. Переменная FileName инициализирована и содержит имя файла, с должным расширением;

6. Обработка ошибок не ведется, кроме необходимых случаев.

var

 
  F: TextFile;
  FileName: string;
  I: Integer;
  SG: TStringGrid;  
  TempStr: string;
  Y, M, D: Word;
begin
  try
    AssignFile(F, Filename);  // связали файл с переменной
    Rewrite(F);               // создаем пустой файл
// если строка с заголовком не нужна, то можно эту строку удалить.
    WriteLn(F,
      '"', SG.Cells[0, 0], '",',
      '"', SG.Cells[1, 0], '",',
      '"', SG.Cells[2, 0], '"');
    for I := 1 to SG.RowCount – 1 do  // проход по всем строкам 
    begin
      try
// конвертирование строки из регионального в американский формат
        DecodeDate(StrToDate(Trim(SG.Cells[1, I])), Y, M, D);
        TempStr := IntToStr(M)+'/'+ IntToStr(D)+'/'+IntToStr(Y);
      except
        TempStr := ' ';             // дата не указана или неверная
      end;
      WriteLn(F,
        SG.Cells[0, I],             // число
        TempStr,                    // конвертированная дата
        '"', SG.Cells[2, I], '"');  // текст
    end;
  finally
    CloseFile(F);
  end;
end

Как видим код весьма простой, первым WriteLn выводим заголовки таблицы, а поскольку все заголовки это текст, то обрамляем элементы двойными кавычками и разделяем запятой.

Далее в цикле проходим по всем строкам данных и выводим сами данные, но в отличии от строки заголовка делаем следующее:

· Первая колонка у нас число, поэтому выводим, как есть;

· Вторая колонка у нас дата, приводим ее к формату MM/DD/YYYY, но также без кавычек;

· Третья колонка у нас строка, ее выводим в кавычках.

Если дата опущена или неверная, то экспортируем пустое значение.

Пример 2, экспорт в файл в формате Tab Delimited

При выводе в данном формате преобразования не нужны, наша задача состоит в том, чтобы вставить символ табуляции между колонками данных, поэтому код будет еще проще. Заголовки и данные выводятся в едином цикле и разделяются символом табуляции.

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

Умолчания для примера:

1. StringGrid создан и содержит некоторое количество колонок и строк, количество определяется при экспорте;

2. Так как отсутствует информация о типах данных в колонках StringGrid, то будем считать, что первая колонка целое число, вторая это дата в региональном формате и третья колонка это текст, больше колонок у нас нет. Но для экспорта данная информация не нужна.

3. Количество строк зависит от наполнения.

4. Нулевая строка как обычно содержит заголовки колонок.

5. Переменная FileName инициализирована и содержит имя файла, с должным расширением;

6. Обработка ошибок не ведется, кроме необходимых случаев.

const
  TAB = #9;     // код символа табуляции
                // константа для удобства
                // можно было бы использовать и #9
var
  F: TextFile;
  FileName: string;
  I: Integer;
  SG: TStringGrid;  
begin
  try
    AssignFile(F, Filename);  // связали файл с переменной
    Rewrite(F);               // создаем пустой файл
 
// если строка с заголовком не нужна, 
// то начните цикл не с нуля, а с единицы.
 
    for I := 0 to SG.RowCount – 1 do  // проход по всем строкам 
    begin
      WriteLn(F,
        SG.Cells[0, I] + TAB + 
        SG.Cells[1, I] + TAB + 
        SG.Cells[2, I]);
    end;
  finally
    CloseFile(F);
  end;
end;

Пример 3, экспорт в файл в формате Fixed

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

Умолчания для примера:

1. StringGrid создан и содержит некоторое количество колонок и строк, количество определяется при экспорте;

2. Так как отсутствует информация о типах данных в колонках StringGrid, то будем считать, что первая колонка целое число, вторая это дата в региональном формате и третья колонка это текст, больше колонок у нас нет. Но для экспорта данная информация не нужна.

3. Количество строк зависит от наполнения.

4. Нулевая строка как обычно содержит заголовки колонок.

5. Переменная FileName инициализирована и содержит имя файла, с должным расширением;

6. Обработка ошибок не ведется, кроме необходимых случаев.

var
  F: TextFile;
  FileName: string;
  I: Integer;
  SG: TStringGrid;  
begin
  try
    AssignFile(F, Filename);  // связали файл с переменной
    Rewrite(F);               // создаем пустой файл
 
// если строка с заголовком не нужна, 
// то начните цикл не с нуля, а с единицы.
 
    for I := 0 to SG.RowCount – 1 do  // проход по всем строкам 
    begin
      WriteLn(F, 
        Format('%-25s %-25s %16s',
        [SG.Cells[0, I], SG.Cells[0, I], SG.Cells[0, I] ]));
    end;
  finally
    CloseFile(F);
  end;
end;

Для выравнивание ширины колонок использована функция Format, вместо встроенного выравнивания WriteLn, поскольку последняя добавляет пробелы слева, а нам нужны пробелы справа. Вместо функции Format можно использовать свою функцию, или функции из других библиотек, или из Дельфи. Не важно, что использовать, важно чтобы строки были дополнены справа пробелами до нужной длины.

Разберем форматную строку

%-25.25s – Символ % это признак спецификатора формата, символ «-» означает выравнивание влево, 25 означает, что длина будет дополняться до 25 символов, а .25 означает максимальное количество символов в строке будет 25, остальные символы будут отбрасываться, символ s указывает на тип данных, в данном случае это означает, что в функцию передается строковое значение.

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

Пример 4, импорт и экспорт данных для TStringList

Остался еще один, последний пример, обеспечения импорта и экспорта данных из таблицы TStringList и обратно. Для этого выберем формат Tab Delimited, как очень экономичный и гибкий для нашей цели. Нам не придется бороться с их количеством, поскольку эти значения будут восстановлены автоматически. Нулевая строка будет содержать всю необходимую информацию о таблице. Единственно, что требуется обеспечить, чтобы все колонки данных в таблице имели свой заголовок.

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

Умолчания для примера:

1. StringGrid создан и содержит некоторое количество колонок и строк, количество определяется во время выполнения;

2. Информация о типах данных в колонках StringGrid отсутствует, но она нам и не нужна, мы должны уметь экспортировать любую информацию.

3. Количество строк зависит от наполнения.

4. Нулевая строка как обычно содержит заголовки колонок.

5. Переменная FileName инициализирована и содержит имя файла, с должным расширением;

6. Обработка ошибок не ведется, кроме необходимых случаев.

const
  TAB = #9;         // код символа табуляции
                             // константа для удобства
                             // можно было бы использовать и #9
procedure Export(const FileName: string;  SG: TStringGrid);
var
  F: TextFile;
  I: Integer;
  J: Integer;
begin
  try
    AssignFile(F, Filename);  // связали файл с переменной
    Rewrite(F);               // создаем пустой файл
    for I := 0 to SG.RowCount – 1 do  // проход по всем строкам 
    begin
      for J := 0 to SG.ColCount – 1 do  // проход по всем колонкам 
      begin
        Write(F,SG.Cells[J, I]);  // пишем отдельную ячейку
        if J < SG.ColCount – 1
        then
          Write(F, TAB)      // тогда пишем разделитель
        else
          WriteLn(F);         // иначе закрываем строку
      end;
    end;
  finally
    CloseFile(F);
  end;
end;
 
procedure Import(const FileName: string; var SG: TStringGrid);
var
  F: TextFile;
  S: string;
begin
  try
    AssignFile(F, Filename);  // связали файл с переменной
    Reset(F);                 // открываем файд с данными
    SG.ColCount := 1;         // начальные значения
    SG.RowCount := 1;         // количества колонок и строк
    while not EOF(F) do       // проход по всем строкам 
    begin
      ReadLn(F, S);           // читаем строку данных
      SG.Col := 0;            // проход всегда начинается с нуля
      while Pos(TAB, S) > 0 do
      begin                              // вычленение колонок
        SG.Cells[SG.Col, SG.Row] := Copy(S, 1, Pos(TAB, S) - 1);
        Delete(S, 1, Pos(TAB, S));
        if SG.ColCount - SG.Col = 1
        then
        begin
          SG.ColCount := SG.ColCount + 1;// нужна новая колонка
        end;
        SG.Col := SG.Col + 1;            // следующая колонка
      end;
      SG.Cells[SG.Col, SG.Row] := S;     // последняя колонка
      SG.RowCount := SG.RowCount + 1;    // добавим еще одну строку
      SG.Row := SG.Row + 1;              // следующая строка
    end;
    SG.RowCount := SG.RowCount - 1;      // лишняя строка
  finally
    SG.FixedCols := 1;                   // восстанавливаем 
    SG.FixedRows := 1;                   // значение по умолчанию
    CloseFile(F);
  end;
end;

Рекомендация: Если необходимо сохранить ширину колонок, количество фиксированных строк и колонок или другие характеристики, то перед импортом сохраните эти значения, а после восстановите их, или установите в нужное значения. После импортирования эти параметры устанавливаются в значение по умолчанию.

Прочитано 11912 раз

Авторизация



Счетчики