Pergunta sobre utf-8, c++, fstream, unicode, windows – fstream :: open () Caracteres Unicode ou Não Ascii não funcionam (com std :: ios :: out) no Windows

3

Em um projeto C ++, quero abrir um arquivo (fstream::open()) (o que parece ser um grande problema). A compilação do Windows do meu programa falha miseravelmente.

Arquivo "ä" (UTF-8 0xC3 0xA4)

<code>std::string s = ...;
//Convert s
std::fstream f;
f.open(s.c_str(), std::ios::binary | std::ios::in); //Works (f.is_open() == true)
f.close();
f.open(s.c_str(), std::ios::binary | std::ios::in | std::ios::out); //Doesn't work
</code>

A cordas é codificado em UTF-8, mas depois convertido de UTF-8 para Latin1 (0xE4). Estou usando o Qt, entãoQString::fromUtf8(s.c_str()).toLocal8Bit().constData().

Por que eu posso abrir o arquivo para leitura, mas não para escrever?

Arquivo "è" (UTF-8 0xD0 0xB8)

O mesmo código, não funciona de todo.

Parece que esse caractere não se encaixa no conjunto de caracteres do Windows-1252. Como posso abrir um tal fstream (eu não estou usando o MSVC, entãonãofstream::open(const wchar_t*, ios_base::openmode))

Resposta longa para breve comentário: verutf8everywhere.org sobre como fazer isso direito. Pavel Radzivilovsky
Que compilador e biblioteca C você está usando? Se você está usando, digamos, MinGW, você ainda pode usar funções do MS CRT, como_wfopen. Se você estiver usando um tempo de execução C diferente (como o libc do Cygwin GCC), estará à mercê do suporte Unicode da biblioteca de tempo de execução. Adam Rosenfield
Sua biblioteca padrão C e C ++ precisa suportar Unicode (ou seja, eles precisam converter suas strings de entrada UTF-8 em UTF-16 e, em seguida, chamarCreateFileW). Se não, você está sem sorte - então, provavelmente, você precisa ligarCreateFileW diretamente. Philipp
@ basic6: Eu infelizmente não sei se há uma maneira de fazer isso. Existe ostd::wfstream classe, mas suaopen método também leva apenas umconst char* para o nome do arquivo. Se você quiser ser capaz de abrir nomes de arquivos Unicode, você precisará usar a biblioteca stdio de C, ou bufferizar completamente os dados do arquivo, lendo-os todos na memória e usando umstd::stringstream para analisar os dados. Adam Rosenfield

Sua resposta

2   a resposta
3

Usando as APIs padrão (como std :: fstream) no Windows, você só pode abrir um arquivo se o nome do arquivo puder ser codificado usando a "Página de código ANSI" atualmente definida (CP_ACP).

Isso significa que pode haver arquivos que simplesmente não podem ser abertos usando essas APIs no Windows. A menos que a Microsoft implemente suporte para configuração de CP_ACP para CP_UTF8, isso não pode estar usando a implementação da biblioteca padrão CRT ou C ++ da Microsoft.

(O Windows tem um recurso chamado de "abreviados" nomes de arquivos onde, quando habilitado, cada arquivo na unidade tinha um nome de arquivo ASCII que pode ser usado através de APIs padrão. No entanto, esse recurso está indo embora, portanto, não representa uma solução viável).

3

Em implementações da Microsoft de STL, há uma extensão não padrão (sobrecarga) para permitir suporte unicode para cadeias codificadas UTF-16.

Apenas passe o std :: wstring codificado em UTF-16 para fstream :: open (). Esta é a única maneira de fazê-lo funcionar com o fstream.

Você pode ler mais sobre o que eu acho ser a maneira mais fácil de suportar unicode no windows aqui:http://utf8everywhere.org/

@ basic6: por favor leia ofunções de conversão seção. AFAIK a biblioteca agora deve funcionar no MinGW também. ybungalobill
Essa é provavelmente a solução apropriada, mas a AFAIK esta sobrecarga só está disponível com o MSVC, não com o MinGW ("nenhuma função correspondente para chamada a ..."). E eu não uso o compilador da Microsoft, porque eu não tenho portado o código no qual estou atualmente trabalhando para o C ++ da Microsoft (em outras palavras, o código não compilará e ainda não me preocupei em descobrir por quê). basic6

Perguntas relacionadas