Zapis pliku CSV w stronie kodowej CP1250

0

Witam

Zapisuję zawartość StringList (zmienna "csv") do pliku csv:

csv.SaveToFile(SaveDialog1.FileName+'.csv'); 

Sam plik jest zapisywany bez problemu, jednak jest oczywisty problem z kodowaniem zawartości samego pliku. Kodowanie w pliku to pewnie UTF8, a Excel domyślnie odczytuje to pewnie w CP1250. Jest jakiś sposób na zapis takiego pliku w CP1250, ew. może macie jakiś inny pomysł, bo kombinuję już kilka dni i nie mogę nic sensownego wymyślić...

Lazarus 1.4.2, FPC 2.6.4.

1

Bo LCL to obsługuje i to co zapiszesz później będzie w UTF-8. Musisz użyć UTF8ToSys, i przekonwertować zanim najpierw zapiszesz to CSV.

0

Nie wiem czy dobrze kombinuję, ale konwertuję to przy "montowaniu" StringList:

var
  csv: TStringList;
  i, j, index: integer; 

csv.add('');
    for i := 0 to StringGrid1.Columns.Count - 1 do begin
        csv[0] := UTF8ToSys(csv[0] + '"' + StringGrid1.Columns[i].Title.Caption + '";');
    end;

    index := 1;
    for i := 0 to StringGrid1.RowCount - 1 do begin
        csv.add('');
       for j := 0 to StringGrid1.Columns.Count - 1 do begin
            csv[index] := UTF8ToSys(csv[index] + '"' + StringGrid1.Cells[j,i] +'";');
        end;
        inc(index);
    end;


    if save.Execute then
    begin
      if FileExists(save.FileName+'.csv') then
        begin
          if MessageDlg('UWAGA','Plik o takiej nazwie już istnieje! Czy napisać?', mtConfirmation, [mbok, mbcancel], 0) = mrOk then
          begin
            csv.SaveToFile(save.FileName+'.csv');
            MessageDlg('INFORMACJA','Zawartość bazy została jako plik CSV: ' + #10 + save.FileName+'.csv', mtInformation, [mbok], 0);
          end;
        end
      else
        begin
          csv.SaveToFile(save.FileName+'.csv');
          MessageDlg('INFORMACJA','Zawartość bazy została jako plik CSV: ' + #10 + save.FileName+'.csv', mtInformation, [mbok], 0);
        end;
    end;  

Efekt mam taki, że teraz zamiast krzaków w miejsce polskich znaków mam teraz same pytajniki. Otwarłem tego csv w Notepadzie++, widzę tam kodowanie w Ansi (Ansi to CP1250?) ale też są pytajniki...
Co skopałem?

1

Jakoś dziwnie to robisz. Ja zrobiłem test pod Lazarusem 64 bitowym jaki posiadam. Mam w Edit1 tekst Łączkę. Gdy zapiszę go normalnie bez konwersji mam plik wynikowy 11 bajtowy bez BOM'u i widać, że na pewno kodowaniem jest raczej UTF8. Ale gdy zrobię tak jak poniżej mam plik 8 bajtowy czyli wyraz plus znak końca linii. Poza tym w bezsensowny sposób robisz u siebie zapis do pliku. Po co sprawdzać czy plik już istnieje i ostrzegać po swojemu? Jeżeli funkcje tę, może "przejąć" sam SaveDialog z odpowiednią flagą we własności Options. Konkretnie ofOverwritePrompt.

var
  SL : TStringList;
begin
  SL := TStringList.Create;
  SL.Text := UTF8ToAnsi(Edit1.Text);
  SL.SaveToFile('D:\test.txt');
  SL.Free;
end;
1

@wotik - ale jest w ogóle jakiś konkretny powód, dla którego wolisz dużo uboższe kodowanie wykorzystać? Dla Lazarusa ( i oczywiście całego LCL) natywnym kodowaniem jest UTF-8 i ono zapewnia wsparcie pełnego zestawu znaków; Pełnego, a nie ASCII i trochę diakrytycznych czy łacińskich; Unikod od nastu lat to standard, więc nie ma sensu upośledzać aplikacji tylko dlatego, że parę bajtów więcej znajdzie się w pliku; Poza tym UTF-8 nie będzie zależne od lokalnej strony kodowej, więc i uniwersalne;

Kodowanie w pliku to pewnie UTF8, a Excel domyślnie odczytuje to pewnie w CP1250. Jest jakiś sposób na zapis takiego pliku w CP1250, ew. może macie jakiś inny pomysł, bo kombinuję już kilka dni i nie mogę nic sensownego wymyślić...

Tak, kodowanie to na pewno UTF-8, jeśli w kodzie nie wykonywałeś konwersji;

Być może Excel nie próbuje wyświetlać zawartości pliku w jego kodowaniu, dlatego że potrzebuje do tego znacznika BOM; Spróbuj więc dodać ten znacznik na początku pierwszej linii i wtedy wczytać plik do arkusza:

const
  UTF8_BOM_SIGNATURE = UTF8String(#239#187#191);
var
  slCSV: TStringList;
begin
  { utworzenie listy, uzupełnienie jej danymi w odpowiedniej strukturze }

  slCSV[0] := UTF8_BOM_SIGNATURE + slCSV[0];
  slCSV.SaveToFile({nazwa pliku});
end;

Spróbuj tak - może w tym diabeł tkwi;


Jeszcze jedna mała uwaga co do tej linijki:

csv.SaveToFile(SaveDialog1.FileName + '.csv');

Jeżeli użytkownik wpisze w polu okna dialogowego tylko nazwę pliku, czyli np. my file, to właściwość FileName zwróci pełną ścieżkę pliku w postaci np. C:\my file.csv; Natomiast jeżeli poda nazwę pliku razem z rozszerzeniem, np. my file.csv to Twój kod niepotrzebnie doda rozszerzenie i wyjdzie np. C:\my file.csv.csv;

Najpierw powinieneś sprawdzić czy faktycznie na końcu ciągu z właściwości FileName znajduje się docelowe rozszerzenie i jeśli nie to je zmienić lub dodać;


I jeszcze jedna mała uwaga - istnieją gotowe biblioteki dla Lazarusa do obsługi plików CSV, więc poszukaj sobie w takiej, pobierz i używaj; Tam zapewne jest wszystko oprogramowane tak, że nie będzie problemu z kodowaniem pod Excelem.

0
furious programming napisał(a):

Być może Excel nie próbuje wyświetlać zawartości pliku w jego kodowaniu, dlatego że potrzebuje do tego znacznika BOM; Spróbuj więc dodać ten znacznik na początku pierwszej linii i wtedy wczytać plik do arkusza:

Bingo. To rozwiązało problem :D.

Dzięki wielkie!

1 użytkowników online, w tym zalogowanych: 0, gości: 1