Автор: de1phi | 18.12.2007 в 10:22 | Рубрики: ASCII

В том случае, когда вы собираетесь использовать содержимое текстового файла таким образом, как будто он имеет поля, вам необходим файл схемы, содержащий описание формата текстового файла и который необходим для осуществления вызовов при работе с полями (Fields / FieldByName / Post / и др.). Ниже приводится код, который вы можете использовать при создании своей программы:

{ Подразумеваем, что Table1 - файл, который мы хотим скопировать
в ASCII-файл. Используем TBatchMove, поскольку быстро работает.
Также это автоматически создаст файл схемы }

procedure TForm1.Button1Click(Sender: TObject);
var

oDest: TTable;
oBMove: TBatchMove;
begin

try
oDest := nil;
oBMove := nil;
Table1.Close;

oDest := TTable.Create(nil);
with oDest do
begin
DatabaseName := ‘c:\delphi\files’;
TableName := ‘Test.Txt’;
TableType := ttASCII;
end; {Обратите внимание на то, что нет необходимости вызывать CreateTable}

oBMove := TBatchMove.Create(nil);
with oBMove do
begin
Source := Table1;
Destination := oDest;
Mode := batCopy;
Execute;
end;
finally
if Assigned(oDest) then
oDest.Free;
if Assigned(oBMove) then
oBMove.Free;
end;
end;

{ Теперь, допустим, файл схемы существует;
сам текстовый файл может как быть, так его может и не быть.
С помощью файла схемы мы уже можем работать с полями }

procedure TForm1.Button2Click(Sender: TObject);
var

oTxt: TTable;
i: Integer;
f: System.Text;
begin

try
oTxt := nil;

if not FileExists(’c:\delphi\files\Test.Txt’) then
begin
AssignFile(f, ‘c:\delphi\files\Test.Txt’);
Rewrite(f);
CloseFile(f);
end;

oTxt := TTable.Create(nil);
with oTxt do
begin
DatabaseName := ‘c:\delphi\files’;
TableName := ‘Test.Txt’;
TableType := ttASCII;
Open;
end;

with Table1 do
begin
DisableControls;
if not Active then
Open;
First;
while not EOF do
begin
oTxt.Insert;
{ В данном случае файл схемы описывает формат текстового файла; в этом
примере фактически один к одному воспроизводятся поля таблицы
в логическое определение полей в .sch-файле }
for i := 0 to FieldCount - 1 do
oTxt.Fields[i].AsString := Fields[i].AsString;
oTxt.Post;
Next;
end;
end;
finally
Table1.EnableControls;
if Assigned(oTxt) then
oTxt.Free;
end;

end;

Автор: de1phi | в 10:22 | Рубрики: ASCII

Вопрос:
- Помогите найти “дрoва” на крышку от батареек у радиомыши.

Использование драйвера ASCII для файлов с разделительной запятой

Delphi (и BDE) имеют способность использовать ASCII файлы для хранения таблиц. Драйвер ASCII имеет возможность транслировать значения данных ASCII-поля фиксированной длины или файла с разделительной запятой в поля и величины, которые могут отображаться компонентом TTable. Трансляция ASCII файла целиком зависит от сопровождающего файла схемы (Schema File). Файл схемы для файла ASCII данных определяет различные атрибуты, необходимые для преобразования данных ASCII файла в значения отдельных полей. Определения полей для файла с ASCII полями фиксированной длины достаточно простая задача, необходимо знать позиции всех полей, для всех строк они одинаковы. Для файлов с разделительной запятой данный процесс чуть более усложнен из-за того, что не все данные в таком файле во всех строках имеют одинаковую длину. Данный совет как раз и концентрируется на описании этой трудной темы, связанной с чтением данных из файлов с разделительной запятой, имеющих варьируемую длину поля.

Файл схемы

Файл схемы для файла данных ASCII содержит информацию, которая определяет оба типа файла (версии с разделительной запятой и полем с фиксированной длиной), а также определяет поля, которые представлены значениями данных в каждой строке файла данных ASCII. (Все поля файла схемы нечуствительны к регистру, поэтому написание “ascii” равнозначно написанию “ASCII”.) Для того, чтобы файл схемы был признан в качестве такового, он должен иметь то же имя, что и файл данных ASCII, для которого он содержит схему, но иметь расширение .SCH (SCHema - схема). Атрибуты описания файла:

File name: Располагаемый в квадратных скобках, данный атрибут определяет
имя файла ASCII данных (с расширением имени файла,
которое должно быть .TXT).

Filetype: Определяет, имеет ли файл ASCII данных структуру файла с
полями фиксированной длины (используется атрибут FIXED) или
файлом с разделительной запятой (со значениями данных, которые
потенциально могут изменять длину (используется атрибут VARYING).

Delimiter: Определяет символ, которым “окантуривают” значения данных типа
String (обычно двойные кавычки, десятичный ASCII код 34).

Separator: Определяет символ, который используется для разделения отдельных
значений данных (обычно запятая). Данный символ должен быть
видимым символом, т.е. не может быть пробелом (десятичный ASCII
код 32).

CharSet: Определяет драйвер языка (используется атрибут ASCII).
Расположенные ниже атрибуты файла являются определениями поля, задающими правила для каждой строки файла данных ASCII. Данные определения служат источником информации для Delphi и BDE, первоначально необходимой для создания виртуального поля в памяти, в свою очередь служащее для хранения значений данных; тип данных виртуального поля определяется после чтения и трансляции данных из ASCII файла, определения размера и применения атрибутов. Различные атрибуты, определяющие поле файла данных ASCII:

Field: Имя виртуального поля (всегда будет “Field”), сопровождаемое
целым числом, определяющим порядковый номер поля относительно
других полей в файле данных ASCII. Например, первое поле -
Field1, второе Field2, и т.д..

Field name: Определяет выводимое имя поля, отображаемое в виде
заголовка колонки в TDBGrid. Соглашения имен для
таблиц ASCII такие же, как и для таблиц Paradox.

Field type: Определяет, какой тип данных BDE должен использоваться при
трансляции значений данных каждого поля и сообщает
Delphi тип виртуального поля, которое необходимо создать.

Используйте определение Для значений типа
———————– —————————-
CHAR Символ
FLOAT 64-битное число с плавающей точкой
NUMBER 16-битное целое
BOOL Boolean (T или F)
LONGINT 32-битное длинное целое
DATE Поле Date.
TIME Поле Time.
TIMESTAMP Поле Date + Time.

(Фактически формат для значений данных даты и времени
будет определяться текущими настройками конфигурации BDE,
страница с закладкой Date.)

Data value length: Максимальная длина значения данных соответствующего поля.
Данный атрибут определяет длину виртуального поля,
создаваемое Delphi для получения считываемых значений из
ASCII-файла.

Number of decimals: Приложение к полю типа FLOAT; определяет количество цифр
справа от десятичной точки; необходимо для включения в
определение виртуального поля.

Offset: Отступ от начала строки, позиция начала данных описываемого
поля; задается для всех строк файла.
Например, приведенное ниже определение поля относится к первому полю таблицы ASCII. Данная строка определяет значения данных типа String с именем “Text”, максимальная длина значения данных составляет три символа (и в Delphi компонентах для работы с базами данных, типа TDBGrid, поле будет отображаться только тремя символами), десятичный порядок (значение данных типа String никогда не сможет иметь десятичные значения, тем более после запятой), и смещение относительно нулевой позиции (поскольку описываемая область первая, то она сама начинается с нулевой позиции, перед ней не находится ни одно поле).

Field1=Text,Char,3,00,00
Вот пример файла схемы с тремя полями, первое поле имеет тип String, второе и третье тип Date. Данный файл схемы должен содержаться в файле с именем DATES.SCH и обеспечивать определения полей для файла данных ASCII с именем DATES.TXT.
[DATES]
Filetype=VARYING
Delimiter=”
Separator=,
CharSet=ascii
Field1=Text,Char,3,00,00
Field2=First Contact,Date,10,00,03
Field3=Second,Date,10,00,13
Данная схема определяет поле с разделительной запятой, где все данные могут быть отнесены к типу String, значения полей “окантурены” двойными кавычками и отдельные значения полей разделены запятой (за исключением любых запятых, которые могут находится между разделительными запятыми, внутри отдельных значений полей типа String). Первое поле типа character имеет длину три символа, без определения десятичного порядка и с нулевым отступом от начала строки. Второе поле данных имеет длину 10, без определения десятичного порядка и отступ, равный трем. Третье поле данных имеет длину 10, без определения десятичного порядка и отступ, равный 13.
Для чтения файлов ASCII с разделительной запятой, параметры длины и отступа для определения поля относятся не к значениям данных в файлах ASCII (что явно противоположно для файлов с полями фиксированной длиной), а к виртуальным полям, определяемым в приложении, в котором будет размещены считываемые данные. Параметр длины должен отражать максимальную длину значений данных для каждого поля, не считая огриничительных кавычек и разделительной запятой. Это наиболее трудно при оценке значений данных типа String, поскольку фактическая длина значений данных может быть существенно различаться для каждой строки в файле данных ASCII. Параметр отступа для каждого поля не будет являться позицией значений данных в файле ASCII (что относится к файлам с полями фиксированной длины), а представляет собой совокупную длину всех предыдущих полей (и снова, определение полей в памяти, не значения данных в файле ASCII).

Вот файл данных с именем DATES.TXT, который соответствует описанному выше файлу схемы:

“A”,08/01/1995,08/11/19955
“BB”,08/02/1995,08/12/1995
“CCC”,08/03/1995,08/13/1995
Максимальная длина фактических значений данных в первом поле составляет три символа (”CCC”). Поскольку это первое поле и предшествующих полей не существует, отступ для данного поля равен нулю. Длина первого поля (3) используется в качестве отступа для второго поля. Длина второго поля, значение date, равно 10 и отражает максимальную длину значения данных этого поля. Совокупная длина первого и второго полей используется в качестве значения отступа для третьего поля (3 + 10 = 13).
Только когда соответствующая длина значения данных ASCII файла или длина каждого поля добавляется к длине предыдущих полей, вычисляется значение отступа и получается позиция очередного поля, только тогда данный процесс правильно считает данные. Если из-за неправильных установочных параметров в файле схемы данные транслируются неверно, то в большинстве типов полей могут возникнуть неблагоприятные эффекты типа обрезания строк, или интерпретирование цифр как нулей. Обычно в таком случае данные выводятся, но ошибки не возникает. Тем не менее, значения определенного формата в процессе трансляции в подходящий тип данных могут вызвать ошибку, если считываемые символы не соответствуют символам, например, в типе date. В контексте вышесказанного, ошибка с типом datе может возникнуть и-за того, что при неправильном определении в значения данных могут попасть данные другого, соседнего поля. При таком стечение обстоятельств трансляция данных прерывается, и в файле схемы требуется установка правильной длины поля и его отступа.

Автор: de1phi | в 10:22 | Рубрики: ASCII

В файле asciidrv.txt насчет последнего числа в строке схемы поля говорится:

“* Offset - Number of characters from the beginning of the line that the field begins. Used for FIXED format only.” (Offset - количество символов он начала линии до начала поля. Используется только для фиксированного формата.).

С тех пор, как мой файл имеет переменный (Variable) формат, я задал в каждой строке смещение, равное нулю. После некоторых попыток, чтобы заставить это работать, я следал следующие изменения:

[discs]
filetype = varying
charset = ascii
delimiter = ”
separator = ,
field1 = id,char,10,0,1
field2 = title,char,30,0,2
field3 = artist,char,30,0,3

field36 = song30,char,50,0,36

После более произвольных изменений это стало таким:

[discs]
filetype = varying
charset = ascii
delimiter = ”
separator = ,
field1 = id,char,10,0,10
field2 = title,char,30,0,20
field3 = artist,char,30,0,30

field36 = song30,char,50,0,360

и внезапно все заработало! Для поля, которое игнорируется форматом файла, “Offset” несомненно дало огромный эффект.

Автор: de1phi | в 10:22 | Рубрики: ASCII

unit Cdbascii;

interface

uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, DbiErrs, DbiTypes, DbiProcs, DB, DBTables;

type
TAsciiDelimTable = class(TTable)
private
{ Private declarations }
fQuote: Char;
fDelim: Char;
protected
{ Protected declarations }
function CreateHandle: HDBICur; override;
procedure SetQuote(newValue: Char);
procedure SetDelim(newValue: Char);
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
{ Эти свойства не должны больше публиковаться }
property IndexFieldNames;
property IndexName;
property MasterFields;
property MasterSource;
property UpdateMode;
published
{ Published declarations }
property Quote: Char read fQuote write setQuote default ‘”‘;
property Delim: Char read fDelim write setDelim default ‘,’;
end;

procedure Register;

implementation

uses DBConsts;

procedure Register;
begin
RegisterComponents(’Data Access’, [TAsciiDelimTable]);
end;

constructor TAsciiDelimTable.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Exclusive := True;
TableType := ttASCII;
fQuote := ‘”‘;
fDelim := ‘,’;
end;

destructor TAsciiDelimTable.Destroy;
begin
inherited Destroy;
end;

{ Рабочий код }

function CheckOpen(Status: DBIResult): Boolean;
begin
case Status of
DBIERR_NONE:
Result := True;
DBIERR_NOTSUFFTABLERIGHTS:
begin
if not Session.GetPassword then
DbiError(Status);
Result := False;
end;
else
DbiError(Status);
end;
end;

function TAsciiDelimTable.CreateHandle: HDBICur;
const
OpenModes: array[Boolean] of DbiOpenMode = (dbiReadWrite, dbiReadOnly);
ShareModes: array[Boolean] of DbiShareMode = (dbiOpenShared, dbiOpenExcl);
var
STableName: array[0..SizeOf(TFileName) - 1] of Char;
SDriverType: array[0..12] of Char;
begin
if TableName = ” then
DBError(SNoTableName);
AnsiToNative(DBLocale, TableName, STableName, SizeOf(STableName) - 1);
StrPCopy(SDriverType, ‘ASCIIDRV-’ + Quote + ‘-’ + Delim);
Result := nil;
while not CheckOpen(DbiOpenTable(DBHandle, STableName, SDriverType,
nil, nil, 0, OpenModes[ReadOnly], ShareModes[Exclusive],
xltField, False, nil, Result)) do {Повтор}
;
end;

procedure TAsciiDelimTable.SetQuote(newValue: Char);
begin
if Active then
{ DBError(SInvalidBatchMove); };
fQuote := newValue;
end;

procedure TAsciiDelimTable.SetDelim(newValue: Char);
begin
if Active then
{ DBError(SInvalidBatchMove); };
fDelim := newValue;
end;

end.

Автор: de1phi | в 10:22 | Рубрики: ASCII

Hа боpту самолета:
- Здpавствуйте, дамы и господа, - говоpит командиp экипажа. - Мы благодаpим вас за то, что вы выбpали нашу авиакомпанию для пеpвого полета в пеpвый день нового 2000 года. Мы находимся на высоте 3 тыс. футов, наша скоpость… вау!… ох, блин!… вот фак!… Извините за неудобства, котоpые вы испытываете, находясь вниз головой, надеюсь, все были пpистегнуты. Есть ли сpеди пассажиpов на боpту пpогpаммист?

Классы Tstrings/TStringlist имеют свойство commatext, которое автоматически разделяет строки, содержащие разделители, на отдельные части. Пример показывает как считать CSV файл. В Конечном итоге, автоматически разделённые строки содержатся в TStringlist.

var
ts: tstringlist;
S: string;
Tf: Textfile;
begin
Ts := Tstringlist.create;
Assignfile(tf, ‘filename’);
Reset(tf);
while not eof(tf) do
begin
Readln(tf,S);
Ts.CommaText := S;
//ProcessLine;
end;
closefile(tf);
ts.free;
end;

Так же операцию можно производить в обратном порядке.

Свойство Commatext поддерживает разделители как в виде запятых, так и двойных кавычек: 1,2,3,4 и “1″,”2″,”3″,”4″

Например, строка вида “1″,”2,3″,”4″ будет разделена на три элемента, которые заключены в кавычки (средняя запятая будет проигнорирована). Чтобы включить кавычку в конечный результ, нужно поставить две кавычки подряд: “1″,”"2″ (результат будет 1 и “2 ).

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls, Db, DBTables, Grids, DBGrids;

type
TForm1 = class(TForm)
DBGrid1: TDBGrid;
MyTable: TTable;
DataSource1: TDataSource;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure ExportToASCII;
end;
Читать полностью…

function ConvertTo852(S: string): string;
var
A : integer;
Ch : char;
begin
setlength(Result,Length(S));
for A := 1 to length(S) do
begin
case S[A] of
: Ch := <852code>
: Ch := <852code2>

else Ch := S[A];
end;
Result[A] := Ch;
end;
end;

Автор: de1phi | в 10:22 | Рубрики: ASCII

Приведу несколько простых функций, позволяющих работать с отдельными словами в строке. Возможно они пригодятся вам для разбивки текстовых полей на отдельные слова (for i := 1 to NumToken do …) с последующим сохранением их в базе данных.

function GetToken(aString, SepChar: string; TokenNum: Byte): string;
{
параметры: aString : полная строка

SepChar : единственный символ, служащий
разделителем между словами (подстроками)
TokenNum: номер требуемого слова (подстроки))
result : искомое слово или пустая строка, если количество слов

меньше значения ‘TokenNum’
} Читать полностью…

Автор: de1phi | в 10:22 | Рубрики: ASCII

Скачивание файла.
Размер: неизвестно (скачено 45%).

var s: String; f: TextFile;
AssignFile(f, ‘D:\\INPUT.TXT);
Reset(f);
while not EOF(f) do
begin
ReadLn(s, f);
ShowMessage(GetField(s, 1)); {The first field\}
ShowMessage(GetField(s, 6)); {The sixth field\}
ShowMessage(GetField(s, 25)); {will return ” if no 25 column…\}
end;
CloseFile(f);

{ ==== This function will return a field from a delimited string. ==== \}
function GetField(InpString: String; fieldpos: Integer): String;
var
c: Char;
curpos, i: Integer;
begin
curpos := 1;
for i := 1 to fieldpos do
begin
result := ”; if curpos > Length(InpString) then Break;
repeat
c := InpString[curpos]; Inc(curpos, 1);
if (c = ‘”‘) or (c = #13) or (c = #10) then c := ‘ ‘;
if c <> ‘,’ then result := result + c;
until (c = ‘,’) or (curpos > Length(InpString))
end;
if (curpos > Length(InpString)) and (i < fieldpos) then result := '';
result := Trim(result);
end;

{ ==== This function will trim a string removing spaces etc. ==== \}
function Trim(inp_str: String): String;
var
i: Integer;
begin
for i := 1 to Length(inp_str) do if inp_str[i] <> ‘ ‘ then Break;
if i > 1 then Delete(inp_str, 1, i - 1);
for i := Length(inp_str) downto 1 do if inp_str[i] <> ‘ ‘ then Break;
if i < Length(inp_str) then Delete(inp_str, i + 1, Length(inp_str));
result := inp_str;
if result = ‘ ‘ then result := ”;
end;

Автор: de1phi | в 10:22 | Рубрики: ASCII

function isAscii(NomeFile: string): Boolean;
const
SETT = 2048;
var
i: Integer;
F: file;
a: Boolean;
TotSize, IncSize, ReadSize: Integer;
c: array[0..Sett] of Byte;
begin
if FileExists(NomeFile) then
begin
{$I-}
AssignFile(F, NomeFile);
Reset(F, 1);
TotSize := FileSize(F);
IncSize := 0;
a := True;
while (IncSize < TotSize) and (a = True) do
begin
ReadSize := SETT;
if IncSize + ReadSize > TotSize then ReadSize := TotSize - IncSize;
IncSize := IncSize + ReadSize;
BlockRead(F, c, ReadSize);
// Iterate
for i := 0 to ReadSize - 1 do
if (c[i] < 32) and (not (c[i] in [9, 10, 13, 26])) then a := False;
end; { while }
CloseFile(F);
{$I+}
if IOResult <> 0 then Result := False
else
Result := a;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
if OpenDialog1.Execute then
if isAscii(OpenDialog1.FileName) then
ShowMessage(’ASCII File’);
end;

Автор: de1phi | в 10:22 | Рубрики: ASCII

В Delphi 1.0 для получения количества записей в ASCII файле (.TXT- и .SCH-файлы) я пользовался свойством RecordCount компонента TTable. В Delphi 2.0 эта функциональность не поддерживается! Я прав или не прав? Во всяком случае как мне получить количество записей, содержащихся в ASCII таблице?

В Delphi 2.0, свойство RecordCount отображается на недокументированную функцию BDE DbiGetExactRecordCount. Данное изменение было сделано для обеспечения правильных величин при работе с “живыми” запросами. Очевидно, данное API по какой-то причине не поддерживает текстовые файлы.

Вы можете обойти эту проблему, вызывая функцию API BDE DbiGetRecordCount напрямую (добавьте BDE к списку используемых модулей):

procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word;
var
RecCount: Integer;
begin
Check(DbiGetRecordCount(Table1.Handle, RecCount);
end;

Автор: de1phi | в 10:22 | Рубрики: ASCII

procedure ReadTabFile(FN: TFileName; FieldSeparator:
Char; SG: TStringGrid);
var
i: Integer;
S: string;
T: string;
Colonne, ligne: Integer;
Les_Strings: TStringList;
CountCols: Integer;
CountLines: Integer;
TabPos: Integer;
StartPos: Integer;
InitialCol: Integer;
begin
Les_Strings := TStringList.Create;
try
// Load the file, Datei laden
Les_Strings.LoadFromFile(FN);

// Get the number of rows, Anzahl der Zeilen ermitteln
CountLines := Les_Strings.Count + SG.FixedRows;

// Get the number of columns, Anzahl der Spalten ermitteln
T := Les_Strings[0];
for i := 0 to Length(T) - 1 do Inc(CountCols,
Ord(IsDelimiter(FieldSeparator, T, i)));
Inc(CountCols, 1 + SG.FixedCols);
Читать полностью…