Difference between revisions of "CSV/ru"
(→ZMSQL) |
|||
(5 intermediate revisions by the same user not shown) | |||
Line 33: | Line 33: | ||
=== CsvDocument === | === CsvDocument === | ||
− | [[CsvDocument]] | + | [[CsvDocument/ru|CsvDocument]] является надежной реализацией как CSV-формата RFC 4180 ,так и альтернативного CSV-формата Creativyst/Excel. Он предлагает как линейный, так и документный доступ. Рекомендуется для использования с FPC/Lazarus. См. [[CsvDocument/ru|CsvDocument]]. |
=== DelimitedText === | === DelimitedText === | ||
− | TStringList | + | TStringList предлагает свойство <code>DelimitedText</code>. Оно разбивает строку текста на отдельные поля. Обратите внимание, однако, что <code>DelimitedText</code> должен быть в SDF-формате, специфичном для Delphi, который очень похож на CSV, но не полностью соответствует RFC4180. |
− | + | Совет: при чтении данных CSV установите для свойства ''StrictDelimiter'' значение <code>true</code>. | |
− | + | При записи CSV-данных установите для ''StrictDelimiter'' значение <code>false</code> и выведите свойство ''DelimitedText''. Тут есть одна странность, заключающаяся в том, что, например, символы табуляции удаляются при записи данных с использованием <code>StrictDelimiter:=false</code> | |
− | ==== SDF | + | ==== Формат SDF ==== |
− | + | См. [[SDF#SDF_format|формат SDF]] | |
=== SDFDataset === | === SDFDataset === | ||
− | FreePascal | + | FreePascal предлагает [[TSdfDataSet/ru|TSdfDataSet]], который <s>хранит данные в формате SDF</s>. Примечание: FPC 2.6.x и более ранние версии хранят данные sdfdataset в формате, который не является полностью CSV или SDF-совместимым. Sdfdataset планируется переписать для хранения данных в формате CSV. |
− | + | Как указано, [[SDF]] отличается от CSV. В зависимости от разновидности CSV этот формат может быть достаточно близок к тому, что ожидает от него читающее приложение. | |
− | {{Warning|1=TSDFDataset | + | {{Warning|1=TSDFDataset, скорее всего, не будет работать, по крайней мере, на Windows CE/Windows Mobile на базе ARM, см. [http://bugs.freepascal.org/view.php?id=17871 багрепорт]}} |
− | {{Note|1= | + | {{Note|1=Ноябрь 2012: SDFDataset должен был быть ''(но еще не был)'' переопределен для использования формата RFC4180 CSV. См., например, [http://bugs.freepascal.org/view.php?id=22980 багрепорт]}} |
− | ==== TSdfDataset | + | ==== Файлы с примерами TSdfDataset и TFixedDataset ==== |
− | + | * Пример SDF-файла | |
− | : | + | :Ниже приведен пример базы данных для TSdfDataset. Обратите внимание, что в первой строке указаны имена полей и мы используем запятые в качестве разделителей: |
<pre>ID,NAMEEN,NAMEPT,HEIGHT,WIDTH,PINS,DRAWINGCODE | <pre>ID,NAMEEN,NAMEPT,HEIGHT,WIDTH,PINS,DRAWINGCODE | ||
Line 66: | Line 66: | ||
3,transistor npn,transistor npn</pre> | 3,transistor npn,transistor npn</pre> | ||
− | * | + | * Пример файла TFixedDataset |
− | : | + | :Каждая запись занимает фиксированное количество пробелов, и если поле меньше, пробелы должны использоваться для заполнения оставшегося размера. |
<pre>Name = 15 chars; Surname = 15 chars; e_mail = 20 chars; | <pre>Name = 15 chars; Surname = 15 chars; e_mail = 20 chars; | ||
Piet Pompies piet@pompies.net</pre> | Piet Pompies piet@pompies.net</pre> | ||
− | ==== | + | ==== Использование наборов данных: пример кода ==== |
− | + | Иногда полезно создать набор данных и работать с ним полностью в коде, и следующий код сделает это точно. Обратите внимание на некоторые особенности TSdfDataset/TFixedDataset: | |
− | * | + | * Максимальный размер строк в базе данных может составлять около 300. Проблема в процессе решения. |
− | * | + | * Необходимо добавить определения полей. Некоторые наборы данных могут заполнить эту информацию самостоятельно из файла базы данных. |
− | * | + | * Нужно установить <code>FirstLineAsSchema</code> в <code>true</code>, чтобы указать, что первая строка содержит имена и позиции полей. |
− | * | + | * Свойство <code>Delimiter</code> содержит разделитель для полей. Будет невозможно использовать этот символ в строках в базе данных. Точно так же в настоящее время не будет возможности иметь символа окончания строк в базе данных, поскольку они отмечают изменение между записями. Это можно преодолеть, подставив нужную запятую или окончание строки с другим редко используемым символом, например <b>#</b>. При отображении данных на экране все символы <b>#</b> могут быть преобразованы в окончания строк и наоборот при сохранении данных в базе данных. Здесь будет полезна процедура <code>ReplaceString</code>. |
<syntaxhighlight lang="pascal"> | <syntaxhighlight lang="pascal"> | ||
Line 92: | Line 92: | ||
FDataset := TSdfDataset.Create(nil); | FDataset := TSdfDataset.Create(nil); | ||
FDataset.FileName := vConfigurations.ComponentsDBFile; | FDataset.FileName := vConfigurations.ComponentsDBFile; | ||
− | FDataset.FileMustExist := false; // | + | FDataset.FileMustExist := false; // существующий CSV-файл не требуется |
− | // | + | // Не обязательно с TSdfDataset: |
// FDataset.TableName := STR_DB_COMPONENTS_TABLE; | // FDataset.TableName := STR_DB_COMPONENTS_TABLE; | ||
// FDataset.PrimaryKey := STR_DB_COMPONENTS_ID; | // FDataset.PrimaryKey := STR_DB_COMPONENTS_ID; | ||
− | // | + | // Добавляем определения полей |
FDataset.FieldDefs.Add('ID', ftString); | FDataset.FieldDefs.Add('ID', ftString); | ||
− | // | + | //необходимо добавить схему, чтобы sdfdataset правильно записал заголовок csv: |
FDataset.Schema.Add('ID'); | FDataset.Schema.Add('ID'); | ||
FDataset.FieldDefs.Add('NAMEEN', ftString); | FDataset.FieldDefs.Add('NAMEEN', ftString); | ||
Line 115: | Line 115: | ||
FDataset.Schema.Add('DRAWINGCODE'); | FDataset.Schema.Add('DRAWINGCODE'); | ||
− | // | + | // Необходимо для TSdfDataset |
FDataset.Delimiter := ','; | FDataset.Delimiter := ','; | ||
FDataset.FirstLineAsSchema := True; | FDataset.FirstLineAsSchema := True; | ||
Line 121: | Line 121: | ||
FDataset.Active := True; | FDataset.Active := True; | ||
− | // | + | // Устанавливаем начальную запись |
CurrentRecNo := 1; | CurrentRecNo := 1; | ||
FDataset.First; | FDataset.First; | ||
Line 127: | Line 127: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | При использовании [[TSdfDataSet/ru|TSdfDataSet]] следует помнить, что <code>RecNo</code>, хоть и реализован, но не работает как способ перемещения по набору данных при чтении или записи записей. Стандартные процедуры навигации, такие как <code>First</code>, <code>Next</code>, <code>Prior</code> и <code>Last</code>, работают как и положено, поэтому вам нужно использовать их, а не <code>RecNo</code>. | |
− | + | Если вы привыкли использовать абсолютные номера записей для навигации по базе данных, вы можете реализовать свою собственную версию <code>RecNo</code>. Объявите глобальную переменную <code>longint</code> с именем <code>CurrentRecNo</code>, которая будет содержать текущее значение <code>RecNo</code>. Помните, что эта переменная будет иметь то же соглашение, что и <code>RecNo</code>, поэтому первая запись имеет номер 1 (а не начинается с нуля). После активации базы данных инициализируйте базу данных для первой записи с помощью <code>TSdfDataset.First</code> и установите <code>CurrentRecNo:= 1</code>. | |
− | + | Пример кода: | |
<syntaxhighlight lang="pascal"> | <syntaxhighlight lang="pascal"> | ||
{@@ | {@@ | ||
− | + | Перемещение к нужной записи с использованием TDataset.Next и TDataset.Prior. | |
− | + | Это позволяет избегать использования TDataset.RecNo, который не обеспечивает надежную навигацию в любом наборе данных. | |
− | @param AID | + | @param AID Указывает номер записи. Первая запись имеет номер 1 |
} | } | ||
procedure TComponentsDatabase.GoToRec(AID: Integer); | procedure TComponentsDatabase.GoToRec(AID: Integer); | ||
begin | begin | ||
− | // | + | // Мы находимся перед искомой записью, двигаемся вперед |
if CurrentRecNo < AID then | if CurrentRecNo < AID then | ||
begin | begin | ||
Line 152: | Line 152: | ||
end; | end; | ||
end | end | ||
− | // | + | // Мы находимся после искомой записи, двигаемся назад |
else if CurrentRecNo > AID then | else if CurrentRecNo > AID then | ||
begin | begin | ||
Line 165: | Line 165: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | === | + | === Экспорт данных === |
− | FreePascal/Lazarus | + | Функциональность экспорта базы данных FreePascal/Lazarus (например, TCSVExporter на вкладке «Data Export») предлагает функцию экспорта CSV для наборов данных. |
− | === Jan | + | === CSV компоненты Jan === |
− | + | См. [[JCSV_(Jans_CSV_Components)|JCSV (Jans CSV Components)]]. | |
=== ZMSQL === | === ZMSQL === | ||
− | [[ZMSQL]] | + | [[ZMSQL]] хранит данные в файлах, разделенных точкой с запятой (используя SDF?). |
Latest revision as of 22:50, 15 July 2020
│
English (en) │
русский (ru) │
Обзор
CSV означает Comma-Separated Values (значения, разделенные запятыми) и является популярным форматом файлов, который, к сожалению, не полностью стандартизирован.
Это текстовый формат файла с
- полями данных, разделенными запятыми (или, в некоторых случаях, другими символами, такими как табуляции и точки с запятой)
- строкой заголовка, в которой перечислены имена полей (которой может и не быть)
- данными полей, содержащих разделители, которые могут быть запрещенными или быть заключенными в кавычки (чаще всего это знак двойной кавычки)
- окончаниями строк (#13 и/или #10), которые могут или не могут быть разрешены в данных полей
RFC4180 (см.здесь) пытается кодифицировать и стандартизировать существующую практику; имеет смысл соответствовать этому стандарту при записи данных CSV (и принимать все данные RFC4180 при чтении).
Другая, альтернативная, спецификация может быть найдена здесь
Образец фрагмента CSV:
FirstName,Surname,DOB,Remarks Jim,Weston,19560818,"Also known as ""The Butcher""" Alice,Cooper,19760312,""
Как видно, здесь используется строка заголовка, как и квотирование с использованием двойных кавычек.
Пакеты электронных таблиц, такие как Microsoft Excel и OpenOffice/LibreOFfice Calc, могут экспортировать и импортировать из этого формата. Однако, поскольку Microsoft Excel может интерпретировать некоторые поля, такие как поля даты, по-разному в зависимости от языкового стандарта операционной системы пользователя, возможно целесообразнее найти альтернативные способы передачи данных (например, используя код FPSpreadsheet).
CSV и SDF
Delphi (и FreePascal) имеют очень похожий (но не идентичный) формат SDF. См. SDF для получения более подробной информации.
Реализации
CsvDocument
CsvDocument является надежной реализацией как CSV-формата RFC 4180 ,так и альтернативного CSV-формата Creativyst/Excel. Он предлагает как линейный, так и документный доступ. Рекомендуется для использования с FPC/Lazarus. См. CsvDocument.
DelimitedText
TStringList предлагает свойство DelimitedText
. Оно разбивает строку текста на отдельные поля. Обратите внимание, однако, что DelimitedText
должен быть в SDF-формате, специфичном для Delphi, который очень похож на CSV, но не полностью соответствует RFC4180.
Совет: при чтении данных CSV установите для свойства StrictDelimiter значение true
.
При записи CSV-данных установите для StrictDelimiter значение false
и выведите свойство DelimitedText. Тут есть одна странность, заключающаяся в том, что, например, символы табуляции удаляются при записи данных с использованием StrictDelimiter:=false
Формат SDF
См. формат SDF
SDFDataset
FreePascal предлагает TSdfDataSet, который хранит данные в формате SDF. Примечание: FPC 2.6.x и более ранние версии хранят данные sdfdataset в формате, который не является полностью CSV или SDF-совместимым. Sdfdataset планируется переписать для хранения данных в формате CSV.
Как указано, SDF отличается от CSV. В зависимости от разновидности CSV этот формат может быть достаточно близок к тому, что ожидает от него читающее приложение.
Предупреждение: TSDFDataset, скорее всего, не будет работать, по крайней мере, на Windows CE/Windows Mobile на базе ARM, см. багрепорт
Файлы с примерами TSdfDataset и TFixedDataset
- Пример SDF-файла
- Ниже приведен пример базы данных для TSdfDataset. Обратите внимание, что в первой строке указаны имена полей и мы используем запятые в качестве разделителей:
ID,NAMEEN,NAMEPT,HEIGHT,WIDTH,PINS,DRAWINGCODE 1,resistor,resistor,1,1,1,LINE 2,capacitor,capacitor,1,1,1,LINE 3,transistor npn,transistor npn
- Пример файла TFixedDataset
- Каждая запись занимает фиксированное количество пробелов, и если поле меньше, пробелы должны использоваться для заполнения оставшегося размера.
Name = 15 chars; Surname = 15 chars; e_mail = 20 chars; Piet Pompies piet@pompies.net
Использование наборов данных: пример кода
Иногда полезно создать набор данных и работать с ним полностью в коде, и следующий код сделает это точно. Обратите внимание на некоторые особенности TSdfDataset/TFixedDataset:
- Максимальный размер строк в базе данных может составлять около 300. Проблема в процессе решения.
- Необходимо добавить определения полей. Некоторые наборы данных могут заполнить эту информацию самостоятельно из файла базы данных.
- Нужно установить
FirstLineAsSchema
вtrue
, чтобы указать, что первая строка содержит имена и позиции полей. - Свойство
Delimiter
содержит разделитель для полей. Будет невозможно использовать этот символ в строках в базе данных. Точно так же в настоящее время не будет возможности иметь символа окончания строк в базе данных, поскольку они отмечают изменение между записями. Это можно преодолеть, подставив нужную запятую или окончание строки с другим редко используемым символом, например #. При отображении данных на экране все символы # могут быть преобразованы в окончания строк и наоборот при сохранении данных в базе данных. Здесь будет полезна процедураReplaceString
.
uses sdfdata, db;
constructor TComponentsDatabase.Create;
var
FDataset: TSdfDataset;
begin
inherited Create;
FDataset := TSdfDataset.Create(nil);
FDataset.FileName := vConfigurations.ComponentsDBFile;
FDataset.FileMustExist := false; // существующий CSV-файл не требуется
// Не обязательно с TSdfDataset:
// FDataset.TableName := STR_DB_COMPONENTS_TABLE;
// FDataset.PrimaryKey := STR_DB_COMPONENTS_ID;
// Добавляем определения полей
FDataset.FieldDefs.Add('ID', ftString);
//необходимо добавить схему, чтобы sdfdataset правильно записал заголовок csv:
FDataset.Schema.Add('ID');
FDataset.FieldDefs.Add('NAMEEN', ftString);
FDataset.Schema.Add('NAMEEN');
FDataset.FieldDefs.Add('NAMEPT', ftString);
FDataset.Schema.Add('NAMEPT');
FDataset.FieldDefs.Add('HEIGHT', ftString);
FDataset.Schema.Add('HEIGHT');
FDataset.FieldDefs.Add('WIDTH', ftString);
FDataset.Schema.Add('WIDTH');
FDataset.FieldDefs.Add('PINS', ftString);
FDataset.Schema.Add('PINS');
FDataset.FieldDefs.Add('DRAWINGCODE', ftString);
FDataset.Schema.Add('DRAWINGCODE');
// Необходимо для TSdfDataset
FDataset.Delimiter := ',';
FDataset.FirstLineAsSchema := True;
FDataset.Active := True;
// Устанавливаем начальную запись
CurrentRecNo := 1;
FDataset.First;
end;
При использовании TSdfDataSet следует помнить, что RecNo
, хоть и реализован, но не работает как способ перемещения по набору данных при чтении или записи записей. Стандартные процедуры навигации, такие как First
, Next
, Prior
и Last
, работают как и положено, поэтому вам нужно использовать их, а не RecNo
.
Если вы привыкли использовать абсолютные номера записей для навигации по базе данных, вы можете реализовать свою собственную версию RecNo
. Объявите глобальную переменную longint
с именем CurrentRecNo
, которая будет содержать текущее значение RecNo
. Помните, что эта переменная будет иметь то же соглашение, что и RecNo
, поэтому первая запись имеет номер 1 (а не начинается с нуля). После активации базы данных инициализируйте базу данных для первой записи с помощью TSdfDataset.First
и установите CurrentRecNo:= 1
.
Пример кода:
{@@
Перемещение к нужной записи с использованием TDataset.Next и TDataset.Prior.
Это позволяет избегать использования TDataset.RecNo, который не обеспечивает надежную навигацию в любом наборе данных.
@param AID Указывает номер записи. Первая запись имеет номер 1
}
procedure TComponentsDatabase.GoToRec(AID: Integer);
begin
// Мы находимся перед искомой записью, двигаемся вперед
if CurrentRecNo < AID then
begin
while (not FDataset.EOF) and (CurrentRecNo < AID) do
begin
FDataset.Next;
FDataset.CursorPosChanged;
Inc(CurrentRecNo);
end;
end
// Мы находимся после искомой записи, двигаемся назад
else if CurrentRecNo > AID then
begin
while (CurrentRecNo >= 1) and (CurrentRecNo > AID) do
begin
FDataset.Prior;
FDataset.CursorPosChanged;
Dec(CurrentRecNo);
end;
end;
end;
Экспорт данных
Функциональность экспорта базы данных FreePascal/Lazarus (например, TCSVExporter на вкладке «Data Export») предлагает функцию экспорта CSV для наборов данных.
CSV компоненты Jan
См. JCSV (Jans CSV Components).
ZMSQL
ZMSQL хранит данные в файлах, разделенных точкой с запятой (используя SDF?).