| Autor | Správa |
jasug
 Užívateľ
 Založený: 05.09.2008 Príspevky: 47
 | Zaslal: Ne 12.09.10 13:13 |   |
Dobrý den,
musím pracovat s dlhými retazcami typu pwidechar ale nemôžem zistit funkcie alebo metody ktoré s nimi pracuju, napr. ekvivalent Length, Write ( file_out, ansi_string) a pod. prosím o radu, kde by som sa to mohol dozvediet. V helpe som našiel iba deklarácie. Vdaka. |
| |
  |
 |
coldak
 Skúsený užívateľ
 Založený: 29.10.2008 Príspevky: 936
 | Zaslal: Ne 12.09.10 15:24 |   |
a odkial mas ze Length nefunguje aj pre PWideChar ? |
| |
  |
 |
jasug
 Užívateľ
 Založený: 05.09.2008 Príspevky: 47
 | Zaslal: Ne 12.09.10 19:16 |   |
Zdravim,
túto konkretne som netestoval, ale ked mám vytvoreny subor file_out ako file a chcem zapísat hodnotu do suboru prikazom write , tak mi vypise chybu pri zapise o nekorektnosti typov.
Neviem ci je problem v type parametra pre write alebo mam hladat niekde inde.
Vdaka. |
| |
  |
 |
coldak
 Skúsený užívateľ
 Založený: 29.10.2008 Príspevky: 936
 | Zaslal: Ne 12.09.10 19:27 |   |
hod sem konkretny kus problemoveho kodu, cize ako declarujes premennu , ako ju naplnas a ako sa ju snazis zapisat do suboru |
| |
  |
 |
Fico
 Skúsený užívateľ
 Založený: 11.01.2009 Príspevky: 1049
 | Zaslal: Ne 12.09.10 22:25 |   |
Skôr, ako začneš pracovať s týmto dátovým typom, by si sa s ním mal trocha oboznámiť, aby ti to uľahčilo prácu. Ak si pracoval s klasickým stringom, tak si možno zaregistroval dátový typ PChar. Je to vlastne smerník na prvý znak v reťazci (string). Príklad:
| kód: | s: string;
c: PChar;
// ...
s:= 'Toto je klasicky reťazec';
c:= @s[1];
ShowMessage( 'Výpis reťazca pomocou smerníka: ' + c ); |
To isté platí aj pre dátový typ PWideChar. Ty ho nemôžeš použiť samostatne. Je to smerník, ktorý musí ukazovať na typ WideChar (prípadne pole 2-bajtových prvkov), teda na prvý znak vo wide reťazci (WideString). Príklad:
| kód: | s: WideString;
p: PWideChar;
// ...
s := 'Velmi dlhy retazec';
p := @s[1];
ShowMessage( 'Výpis reťazca pomocou smerníka: ' + p ); |
Takže po dávke teórie príklad na zápis premennej typu WideString (nie PWideChar, pretože to je smerník) do súboru pomocou streamu:
| kód: | procedure TForm1.Button1Click(Sender: TObject);
var f: TFileStream;
hlavicka: array[0..1] of byte;
begin
s := 'Velmi dlhy retazec';
p := @s[1];
hlavicka[0] := $FF;
hlavicka[1] := $FE;
f := TFileStream.Create( 'E:\skuska.txt', fmCreate OR fmOpenWrite );
try
f.WriteBuffer( hlavicka, 2 );
f.WriteBuffer( p^, length(p) * 2);
finally
f.Free;
end;
end; |
Ešte drobné vysvetlenie: WideString používa UNICODE kódovanie, ktoré v súbore určuje hlavička začínajúca hodnotami 0xFF 0xFE. Každý znak v UNICODE zaberá dva bajty, nie jeden, preto je pri určení dĺžky buffera dvojnásobná dĺžka reťazca.
(*
To bol jednoduchý príklad. Ak používaš dlhé reťazce, možno ti bude výhodnejšie zadeklarovať dynamické pole WideChar znakov, pričom veľkosť si budeš manuálne zväčšovať podľa potreby a postupne znak po znaku ukladať do tohto poľa. Potom by si smerník PWideChar priradil na prvý prvok tohto poľa.
*) |
| |
   |
 |
jasug
 Užívateľ
 Založený: 05.09.2008 Príspevky: 47
 | Zaslal: Ut 14.09.10 23:09 |   |
Dakujem za doterajšie odpovede, poučilo som sa ale na skúšobnom príklade mi dáva výnimku EInvalidPointer pri Freemem. Neviem čo robím zle, vdaka za usmernenie.Prikladám proceduru
procedure TForm1.Button1Click(Sender: TObject);
var
myWideString : WideString;
myWideCharPtr : PWideChar;
i : integer;
begin
myWideString := 'hallo';
myWideCharPtr := Addr(myWideString[1]);
GetMem(myWideCharPtr, Length(myWideString)+1*SizeOf(WideChar));
I:=0;
try
while i<= Length(myWideString) do
begin
StringToWideChar(myWideString, myWideCharPtr,Length(myWideString)+1);
showmessage ('gggg'+myWideCharPtr^);
Inc(i);
showmessage('incre '+inttostr(i));
Inc(myWideCharPtr,2);
end;
finally
FreeMem (myWideCharPtr);
end;
end; |
| |
  |
 |
Fico
 Skúsený užívateľ
 Založený: 11.01.2009 Príspevky: 1049
 |
V riadku:
| kód: | | StringToWideChar(myWideString, myWideCharPtr,Length(myWideString)+1); |
si prepísal adresu v myWideCharPtr a pri dealokovaní je potom nekorektný údaj. Okrem toho prvý parameter funkcie StringToWideChar je typu string - príklad. |
| |
   |
 |
jasug
 Užívateľ
 Založený: 05.09.2008 Príspevky: 47
 |
Vdaka za odpoved, zmenil som program ale určite nie úplne dobre lebo teraz mi hlási AccessViolation na kernel32.dll, môžem poprosit o zhovievavost ?
procedure TForm1.ConvTXTUTF16x;
var
Str_in : char;
str_ins : string ;
Str_out : Widestring;
PStr_out : PWidechar;
Position : LongInt;
begin
Position := 1;
while not eof (FileInx) do
begin
Read (FileInx, Str_in);
Str_ins := Str_in;
PStr_out := Addr (Str_out[1]);
StringToWideChar ( Str_ins, PStr_out, Length (Str_ins)+ 1) ;
// BlockWrite (FileOutx, Str_out, 2);
Inc (Position);
ConvertForm.Gauge1.Progress := Position * 100 div Subor_Length;
Application.ProcessMessages;
end;
ConvertForm.Button1.Caption := 'Konverzia ukonèená';
end; |
| |
  |
 |
Fico
 Skúsený užívateľ
 Založený: 11.01.2009 Príspevky: 1049
 | Zaslal: St 15.09.10 11:07 |   |
AccessViolation ti hlási, lebo smerník PStr_out si priradil prázdnej premennej:
| kód: | | PStr_out := Addr (Str_out[1]); // Str_out nema nastavenu velkost, teda nema ziaden znak |
Upravil som tvoj kód takto (odstránil som z neho signalizačné prvky, aby som to skompiloval, tak si to ešte doplň naspäť):
| kód: | procedure TForm1.Button1Click(Sender: TObject);
var
Str_in : char;
str_ins : string ;
memAlloc: pointer;
PStr_out : PWidechar;
begin
AssignFile( FileInx, 'E:\skuska.txt' );
Reset( FileInx );
GetMem( PStr_out, FileSize( FileInx ) * sizeOf(WideChar) + 1 ); // rezervuj pamat velkosti suboru v bajtoch * 2 + nulovy znak
memAlloc := PStr_out; // zalohuj pointer, lebo sa bude menit
while not eof ( FileInx ) do begin
Read (FileInx, Str_in);
Str_ins:= Str_in;
StringToWideChar( Str_ins, PStr_out, Length (Str_ins)+ 1) ;
inc( PStr_out ); // posunieme sa na dalsi znak
Application.ProcessMessages;
end;
PStr_out^ := WideChar(0); // na koniec nulovy znak
PStr_out := memAlloc; // adresa prveho znaku
// ShowMessage( PStr_out );
CloseFile( FileInx );
FreeMem( memAlloc ); // uvolni pamat
end; |
Poznámka: V kóde som použil funkciu FileSize na získanie veľkosti súboru. Tá sa ale nedá použiť pri TextFile súboroch. Premennú FileInx som zadefinoval ako File of Char, keďže sa z neho čítaju iba znaky. Nezabudni aj na to, že RAM ti klesne po spustení tohto kódu 2-krát viac, ako je veľkosť čítaného súboru. |
| |
   |
 |
jasug
 Užívateľ
 Založený: 05.09.2008 Príspevky: 47
 | Zaslal: St 15.09.10 14:31 |   |
Dakujem Ficovi, perfektne to funguje, musím si riadne pozriet teoriu smerníkov. Ak by som mohol, poprosím ešte o zápis 2 bytov, ktoré sú výsledkom volanej funkcie, do súboru. Výstupný súbor som otváral iba ako file, preto BlockWrite, ale tento spôsob a aj ked ho vytvorím ako file of char mi vyhadzuje chybu, lebo parameter write má byt ansi a ja zapisujem widechar. Velká vdaka. |
| |
  |
 |
coldak
 Skúsený užívateľ
 Založený: 29.10.2008 Príspevky: 936
 | Zaslal: St 15.09.10 14:46 |   |
a skusal si subor definovat ako file of widechar ? |
| |
  |
 |
chrono
 Skúsený užívateľ
 Založený: 13.11.2007 Príspevky: 808
 | Zaslal: St 15.09.10 16:32 |   |
| Fico napísal: | | Ešte drobné vysvetlenie: WideString používa UNICODE kódovanie, ktoré v súbore určuje hlavička začínajúca hodnotami 0xFF 0xFE. Každý znak v UNICODE zaberá dva bajty, nie jeden, preto je pri určení dĺžky buffera dvojnásobná dĺžka reťazca. | Unicode kódovanie neexistuje (teda aspoň ja žiadne také nepoznám). Je to len nezmysel, ktorý možno použil Microsoft (a možno to neboli ani oni, ale používa sa to vo Windows). V skutočnosti ide o kódovanie UCS2 alebo UTF-16 (už netuším, presne ktoré kódovanie sa tam používa). |
| |
  |
 |
Fico
 Skúsený užívateľ
 Založený: 11.01.2009 Príspevky: 1049
 | Zaslal: St 15.09.10 18:54 |   |
| jasug napísal: | | Ak by som mohol, poprosím ešte o zápis 2 bytov, ktoré sú výsledkom volanej funkcie, do súboru |
Skús to tak, ako napísal Coldak, prípadne v totmo príspevku som ti napísal jedno riešenie.
| chrono napísal: | | Unicode kódovanie neexistuje (teda aspoň ja žiadne také nepoznám). Je to len nezmysel, ktorý možno použil Microsoft (a možno to neboli ani oni, ale používa sa to vo Windows). V skutočnosti ide o kódovanie UCS2 alebo UTF-16 (už netuším, presne ktoré kódovanie sa tam používa). |
UNICODE zahŕňa viacero spôsobov kódovaní. Nevedel som presne, ktoré sa tu používa, preto som to napísal všeobecne, že používa UNICODE kódovanie. |
| |
   |
 |
jasug
 Užívateľ
 Založený: 05.09.2008 Príspevky: 47
 | Zaslal: Št 16.09.10 17:29 |   |
Dakujem Ficovi, syntakticky to perfektne funguje, ale mám dve otázky:
ako viem rozlíšiť UTF16, UTF16M a pod. a ako si môžem fyzicky overiť či vytvorený kod je správny napr cez ftp: alebo niečo podobné. Dakujem. |
| |
  |
 |
Fico
 Skúsený užívateľ
 Založený: 11.01.2009 Príspevky: 1049
 | Zaslal: Št 16.09.10 22:32 |   |
Troška priblíž tvoje otázky. Rozlíšiť, aké je kódovanie reťazca v premennej WideString? Ak si myslel to, tak som vygooglil, že tá používa UTF-16 kódovanie. |
| |
   |
 |
|