Właściwie to istnieje bardzo prosty sposób, który działa z plikami CSV i prawidłowo obsługuje cudzysłowy - prawidłowo, czyli jeśli wstawisz tam cudzysłowy jako tekst to zostaną wczytane, w innych przypadkach nie. Jakie to przypadki?
Jeżeli np. wprowadzasz do komórek takie dane:
| tekst 1 | tekst 2 | tekst 3 | to w pliku CSV zostaną zapisane tak:
tekst 1;tekst 2;tekst 3, a do tabeli StringGrid zostaną wczytane tak:
| tekst 1 | tekst 2 | tekst 3 |Jeżeli jednak wprowadzisz takie dane:
| tekst 1 | tekst 2;a | "tekst 3" | to w pliku CSV zostaną zapisane tak:
tekst 1;"tekst 2;a";"""tekst 3"""Jak widać tekst zawierający średnik został ujęty w cudzysłowy, a same cudzysłowy zostały dodatkowo jeszcze ujęte w cudzysłowy. W zaprezentowanych we wcześniejszych postach metodach te cudzysłowy zostaną wczytane jako tekst, czyli komórki będą zawierałby takie treści:
| tekst 1 | "tekst 2 | a" | """tekst 3""" |. Jak widać doszła jeszcze jedna komórka, gdyż tekst zawierający średnik został podzielony na dwie części. Cudzysłowy pozostały.
Ja proponuję metodę, która wczyta dane tak jak wczytane być powinny, czyli:
| tekst 1 | tekst 2;a | "tekst 3" |Pierwszy, szybszy sposób, ale może nie działać w starszej wersji środowiska:
#include "memory" /* biblioteka zawierająca metodę auto_ptr */
void __fastcall LoadFromCSV(String FileName, TStringGrid *Grid)
{
std::auto_ptr<TStringList> fileList(new TStringList);
std::auto_ptr<TStringList> phraseList(new TStringList);
fileList->LoadFromFile( FileName );
phraseList->Delimiter = ';';
phraseList->StrictDelimiter = true;
/* w starszej wersji biblioteki może nie być tej funkcji */
for(int i = 0; i < Grid->RowCount; i++) Grid->Rows[i]->Clear();
Grid->RowCount = fileList->Count;
Grid->ColCount = 2;
/* wiersz i kolumna nagłówka */
Grid->FixedRows = 1;
Grid->FixedCols = 1;
for(int r = 0; r < fileList->Count; r++)
{
phraseList->DelimitedText = fileList->Strings[r];
if( Grid->ColCount < phraseList->Count ) Grid->ColCount = phraseList->Count;
/* w starszej wersji biblioteki może nie być tej funkcji */
Grid->Rows[r]->AddStrings( phraseList.get() );
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
LoadFromCSV("plik.csv", StringGrid1);
}
Drugi sposób, który zadziała w starszych wersjach środowiska, ale działa wolniej:
#include "memory" /* biblioteka zawierająca metodę auto_ptr */
void __fastcall ClearGrid(TStringGrid *Grid)
{
for(int r = 0; r < Grid->RowCount; r++)
{
for(int c = 0; c < Grid->ColCount; c++)
{
Grid->Cells[c][r] = "";
}
}
}
//---------------------------------------------------------------------------
void __fastcall LoadFromCSV(String FileName, TStringGrid *Grid)
{
std::auto_ptr<TStringList> fileList(new TStringList);
std::auto_ptr<TStringList> phraseList(new TStringList);
fileList->LoadFromFile( FileName );
phraseList->Delimiter = ';';
phraseList->StrictDelimiter = true;
ClearGrid(Grid);
Grid->RowCount = fileList->Count;
Grid->ColCount = 2;
/* wiersz i kolumna nagłówka */
Grid->FixedRows = 1;
Grid->FixedCols = 1;
for(int r = 0; r < fileList->Count; r++)
{
phraseList->DelimitedText = fileList->Strings[r];
if( Grid->ColCount < phraseList->Count ) Grid->ColCount = phraseList->Count;
for(int c = 0; c < phraseList->Count; c++)
Grid->Cells[c][r] = phraseList->Strings[c];
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
LoadFromCSV("plik.csv", StringGrid1);
}
U mnie obie funkcje działają bez zarzutu