2010-01-12 2 views
34

WinXP 시스템에서 비영어권 이름으로 파일 이름을 처리하는 프로그래밍을 시작하기 시작했습니다. 유니 코드에 대한 추천 도서를 읽었으며 기본 아이디어를 얻었지만 일부 요소는 여전히 나에게 분명하지 않습니다.NTFS의 파일 이름은 어떤 인코딩으로 저장됩니까?

특히 NTFS에 저장된 (내용은 아니지만 파일의 실제 이름) 파일 인 인코딩 (UTF-8, UTF-16LE/BE)은 무엇입니까? char *를 취하는 fopen()을 사용하여 파일을 열 수 있습니까? 아니면 wchar_t *를 사용하는 wfopen()을 사용하고 아마도 UTF-16 문자열을 사용합니까?

수동으로 UTF-8로 인코딩 된 문자열을 fopen() (예 :

unsigned char filename[] = {0xEA, 0xB0, 0x80, 0x2E, 0x74, 0x78, 0x74, 0x0}; // 가.txt 

FILE* f = fopen((char*)filename, "wb+"); 

는하지만이 'ê ° €이 .txt'로 나왔다.

UTF8로 인코딩 된 문자열이 Windows에서 파일 이름을 여는 데 충분하다는 인상을 받았습니다 (잘못되었을 수 있음). 일부 Windows 응용 프로그램 (varchar *), 아무런 문제가 없습니다.

누구든지이 문제에 대해 의견을 개진 할 수 있습니까?

+0

PHP의 beavior가에 PHP 7.1에서 변경, 정의 유니 코드로 구축하는 프로젝트를 변경하면 변화의 너무 큰 경우 https://stackoverflow.com/a/38466772/680382 – gogowitsch

답변

32

NTFS는 파일 이름을 UTF16으로 저장하지만 fopen은 ANSI (utf8 아님)를 사용합니다.

UTF16으로 인코딩 된 파일 이름을 사용하려면 파일 열기 호출의 유니 코드 버전을 사용해야합니다. 프로젝트에서 UNICODE 및 _UNICODE를 정의하여이 작업을 수행하십시오. 그런 다음 CreateFile 호출 또는 wfopen 호출을 사용하십시오.

+10

를 참조하면 호출 할 수 있습니다'wfopen() '또는'CreateFileW()'를 사용할 수 있습니다. –

+1

Windows NT와 NTFS가 UTF-16 표준보다 오래 되었다면 대신 이전 UCS-2가 사용되었을 가능성이 있습니까? – hillu

+3

NTFS는 0x0000을 제외한 이름 인코딩에 대해 16 비트 값 시퀀스를 허용합니다. 즉, UTF-16 코드 포인트가 지원되지만 파일 시스템은 시퀀스가 ​​유효한 UTF-16인지 여부를 확인하지 않습니다. \ [[source] (https://en.wikipedia.org/wiki/NTFS#Internals) \] – user

13

fopen() - Windows의 MSVC에서 (기본적으로) utf-8로 인코딩 된 char *을 사용하지 않습니다.

유감스럽게도 utf-8은 최근에 사물의 위대한 제도에서 발명되었습니다. Windows API는 유니 코드 및 Ansi 버전으로 나뉩니다. every 문자열을 사용하거나 처리하는 Windows API는 실제로 W 또는 A 접미사와 함께 사용할 수 있습니다. W는 "와이드"문자/유니 코드이고 A는 Ansi입니다. 매크로 매직은 개발자로부터이 모든 것을 숨기고 있기 때문에 차이를 모른 채 빌드 구성에 따라 char * 또는 wchar_t *로 CreateFile을 호출하면됩니다.

'Ansi'인코딩은 실제로 특정 인코딩이 아닙니다. - 그러나 "char"문자열에 사용되는 인코딩은 PC의 로캘 설정에만 해당됩니다.

이제는 fopen과 같은 c-runtime 기능이 개발자 지식없이 기본적으로 작동해야하기 때문에 Windows 시스템에서는 Windows 로컬 인코딩에서 문자열을 수신 할 것으로 예상됩니다. msdn은 Microsoft c-runtime API를 나타냅니다. setlocal은 현재 스레드의 로케일을 변경할 수 있지만 utf-8처럼 문자 당 2 바이트 이상 필요한 모든 로케일에서 실패 할 것이라고 명확히 말합니다.

Windows에서는 바로 가기가 없습니다. 은 wfopen을 사용하거나 기본 API CreateFileW (또는 유니 코드 빌드 설정을 사용하여 Createfile을 호출)을 wchar_t * 문자열로 사용하려면이 필요합니다.

+0

사실, 바로 가기가 있습니다. UTF-8 문자열을 유니 코드로 변환하고, ASCII 전용 "short pathname "을 사용하여 [GetShortPathNameW] (http://msdn.microsoft.com/en-us/library/windows/desktop/aa364989(v=vs.85) .aspx)를 열고 'fopen'에 전달하십시오. 이것은 파일을 열기 위해'fopen'을 사용하는 레거시 라이브러리 (또는 휴대용 C로 작성된 라이브러리)에 ASCII가 아닌 파일 이름을 전달할 수있는 유일한 방법입니다. – user4815162342

3

다른 사람들이 답변 한대로 UTF-8로 인코딩 된 문자열을 처리하는 가장 좋은 방법은 유니 코드로 변환하고 _wfopen 또는 CreateFileW과 같은 기본 유니 코드 API를 사용하는 것입니다.

그러나이 방법은 유니 코드를 지원하지 않거나 휴대용 C로 작성 되었기 때문에 fopen()을 무조건 사용하는 라이브러리를 호출 할 때 도움이되지 않습니다.이 경우 여전히 레거시 "short 경로는 "fopen과 함께 사용할 수있는 ASCII 형태로 UTF-8 인코딩 된 문자열을 변환하는,하지만 몇 가지 마술이 필요합니다

  1. MultiByteToWideChar를 사용하여 UTF-16에 UTF-8 표현을 변환합니다.

  2. GetShortPathNameW을 사용하면 "짧은 경로"를 ASCII 전용으로 사용할 수 있습니다. GetShortPathNameW은 all-ASCII 내용이 포함 된 와이드 문자열로 반환합니다. 각 문자열은 무손실 복사본으로 좁은 문자열로 변환해야합니다 (각각 wchar_tchar).

  3. 단축 경로를 fopen() 또는 결국 fopen()을 사용할 코드로 전달하십시오. 해당 코드에 의해 인쇄 된 오류 메시지는보기 흉한 짧은 경로 (예 : kinto-un-筋斗雲 대신 KINTO~1)를 나타냅니다. 이 권장 장기 전략 정확히 아니지만 윈도우 짧은 경로 당 볼륨을 해제 할 수 있습니다 레거시 기능입니다으로

, 그것은 가능성이 사용하는 코드에 파일 이름을 전달하는 유일한 방법입니다 fopen() 및 기타 파일 관련 API 호출 (stat, access, ANSI 버전 CreateFile 및 유사).

+1

화려한, 당신이 우리를 구했어, 고마워! – Eric

관련 문제