Można podejść tak: Każdy plik jest ciągiem bajtowym, więc można odczytać całą zawartość do listy lub tablicy char
, a potem zamienić na tekst już jakimś algorytmem.
Ja sam miałem dość podobny problem, czyli odczytywanie i zapisywanie tekstu w różnych kodowaniach i podam takiego gotowca:
https://github.com/andrzejlisek/TextPaintWeb/blob/main/prog/textcodec.h
https://github.com/andrzejlisek/TextPaintWeb/blob/main/prog/textcodec.cpp
Przykład użycia obiektu typu TextCodec:
// Zapis pliku:
Codec.get()->Reset();
Codec.get()->AddBOM();
Codec.get()->EnqueueStr(Text);
Codec.get()->DequeueRaw(BinaryData);
// Odczyt pliku:
Codec.get()->Reset();
Codec.get()->EnqueueRaw(BinaryData);
Codec.get()->RemoveBOM();
Codec.get()->DequeueStr(Text);
Idea jest taka, że obiekt konstruuje się numerem kodeka, numery są takie same, jak TextEncoding w C#. Sam kodek działa tak, że w każdej chwili można dopisać dane jako string EnqueueStr
, wewnątrz zamienią się na dane surowe i można wyciągnąć jako dane surowe EnqueueRaw
. Implementację zamiana danych surowych na tekstowe jest w funkcji DequeueStr
. Przy tej implementacji można konwertować tekst fragmentami, nie potrzeba wczytywać od razu całego pliku do kodeka i z niego wyciągać. Kodek też pamięta stan konwersji, bo np. w UTF-8 jeden znak może zajmować 2 lub 3 bajty.
Inaczej mówiąc, można powiedzieć, że kodek działa na zasadzie strumieni, że wchodzi strumień bajtowy i wychodzi strumień tekstowy lub wchodzi strumień tekstowy i wychodzi strumień bajtowy.
Możesz przejrzeć cały projekt, nie widze sensu wstawiać implementacji typów Raw
i Str
, są to odpowiednio tablica danych surowych i odpowiednik zwykłego String. Własne struktury w tym przypadku wynikają z tego, że ja ten program przerabiałem z C# i chciałem mieć interfejs standardowych struktur podobny do tego w C#, a potem dopisywałem dodatkowe funkcje w miare potrzeb.
Myślę, że bez większego trudu można przerobić funkcje kodek tak, żeby wchodziły do nich standardowe struktury, jak np std::vector
do danych surowych i std::string
do tekstu.
Jest jeszcze inny problem: Typ std::string
przeznacza jeden bajt na tekst i w zależności od kompilatora może domyślnie interpretować jako UTF-8 przy cin
i cout
, jestdnak trzeba to mieć na uwadze. Jest to jeszcze jeden powód, dla którego utworzyłem customowy typ Str
, który tak naprawdę jest wektorem liczb i nie ma problemu z dziwnymi znakami. Pierwotnie, w C# też posługiwałem się listą liczb, bo w tym przypadku były jakieś kłopoty przy "egzotycznych" znakach.