Odczyt z pliku UTF-8

Odczyt z pliku UTF-8
KU
  • Rejestracja:ponad 13 lat
  • Ostatnio:ponad 9 lat
  • Postów:102
0
Kopiuj
#ifndef UNICODE
#define UNICODE
#endif

#include <Windows.h>
#include <cstdio>
#include <fstream>

using namespace std;

int main()
{
	FILE* resFile;
	char multiByteStr[256];
	ifstream oFile;
	FILE* exampleFile;
	TCHAR buffer[256];
	
	resFile = _wfopen(L"foo",L"w, ccs=UTF-8");

	system("chcp 65001");

	fwprintf(resFile,L"%s",L"C:\\istniejacyfolder\\zażółć gęśłą jaźń ☺☻♥♦• ć.txt");

	fclose(resFile);

	
	
	oFile.open(L"foo");

	oFile.getline(multiByteStr,256,'\n');
	
	oFile.close();

	MultiByteToWideChar(CP_UTF8,0,multiByteStr,-1,buffer,256);

	wprintf(L"%ls",buffer);

	

	exampleFile = _wfopen(buffer,L"w, ccs=UTF-16LE"); //*
	
	fwprintf(exampleFile,L"%ls",buffer);

	fclose(exampleFile);

	system("pause");
	return 0;
}

W tym wypadku _wfopen zwraca NULL i działanie programu nic nie wnosi.

user image

Przy następnym breakpoincie wyskakuje messageBox "Debug assertion failed".

Co śmieszne, gdy przepiszę ręcznie bufor do funkcji otwierającej plik, tzn.

Kopiuj
 exampleFile = _wfopen(L"C:\\istniejacy folder\\zażółć gęśłą jaźń ☺☻♥♦• ć.txt",L"w, ccs=UTF-16LE"); 

plik tworzy się w prawidłowym miejscu, a wszystkie unikodowe znaki są zachowane. Dlaczego tak się dzieje?

edytowany 1x, ostatnio: kutacz
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 godziny
1

Gdy czytasz treść pliku, na początku możesz napotkać znak U+FEFF (ZERO WIDTH NO-BREAK SPACE). Gdy wczytujesz linię, która potem jest używana jako nazwa pliku, trzeba się go pozbyć.

Kopiuj
wchar_t *buffer_no_bom;
if (buffer[0] == L'\xFEFF')
    buffer_no_bom = &buffer[1];
else
    buffer_no_bom = &buffer[0];

wprintf(L"#%ls#\n",buffer_no_bom);
exampleFile = _wfopen(buffer_no_bom,L"w, ccs=UTF-16LE"); //*
edytowany 3x, ostatnio: Azarien
KU
Sprytnie rozwiązane
KU
  • Rejestracja:ponad 13 lat
  • Ostatnio:ponad 9 lat
  • Postów:102
0

Ano faktycznie :) Dziwna sprawa, plik "foo" zakodował się w UTF-8, a nie UTF-8 without bom . Ale po kiego grzyba BOM w UTF-8? Zawsze myślałem, że w tym kodowaniu kolejność bitów jest jednoznaczna...

edytowany 3x, ostatnio: kutacz
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 godziny
1

Głównie do tego, by po sekwencji bajtów EF BB BF łatwo rozpoznać że to właśnie UTF-8. U ciebie fopen() właśnie to robi, dlatego nie musisz przy otwieraniu podawać ccs=.

RE
Moderator
  • Rejestracja:około 18 lat
  • Ostatnio:około rok
0

Widzę, że okropnie przemieszałeś biblioteki standardowe C, C++ i API Windowsa. Docelowo w C++ obsługa Unicode ma być łatwa i przyjemna, ale póki co jeszcze nie jest. Możliwe do ustawienia locale w runtime biblioteki standardowej C++ pośród swoich "właściwości" (facets) ma codecvt opisujące konwertowanie pomiędzy kodowaniami i właśnie z tego korzystają strumienie plikowe. W C++11 pojawiło się w standardzie m.in. std::codecvt_utf8.

I tak, przykładowo zapisanie i odczytanie jakiegoś napisu mogłoby wyglądać tak:

Kopiuj
locale::global( locale(locale(""), new std::codecvt_utf8<wchar_t>() )); // ustawienie locale domyślnego ze zmienionym `codecvt`

wstring file_name;

{
	wofstream file_output("foo");

	file_output << L"C:\\zażółć gęśłą jaźń ☺☻♥♦• ć.txt";
}

{
	wifstream file_input("foo");
		
	getline(file_input, file_name);
}

W Visual Studio od wersji 2010 nawet to zadziała, ale nawet w GCC 4.7.0 nagłówka codecvt po prostu nie ma i trzeba ratować się #ifdefami, itd..

edytowany 3x, ostatnio: Rev

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.