2016-11-17 2 views
0

В настоящее время я изучаю библиотеку CFFC класса CFile, и у меня есть проблема с записью данных в файл с использованием метода Write. Когда я прохожу обугленного массив в качестве параметра он отлично работает:Нули после каждого символа при записи CString в CFile с использованием элемента записи

char c[] = "Hello!"; 
int size = sizeof(c)/sizeof(c[0]); 
myFile.Write(c, size) 

Символы, которые были написаны в файл:

Hello! 

Но когда я пытаюсь передать объект CString в качестве аргумента:

CString cS("Hello"); 
myFile.Write(cS, cS.GetLength()); 

я получаю:

H e l 

Я также пробовал:

CString cS("Hello"); 
LPWSTR c = cS.GetBuffer(); 
myFile.Write(c, cS.GetLength()); 
cS.ReleaseBuffer(); 

Но выход такой же, как указано выше. Что может быть причиной конверсии? Это происходит, потому что текст хранится в широких символах?

+2

Используйте 'CStringA' вместо' CString'. Широкие символы в диапазоне ASCII состоят из одного байта ASCII и одного нулевого байта. –

ответ

3

Проблема:

Второй параметр CFile::Write это количество байтов, что функция будет передавать от первого параметра (буфер). Вы передаете cS.GetLength(), что скорее передаст количество символов в строке, и это не то же самое, что количество байтов, из которых может состоять сама строка.

Решение:

Вы должны изменить строку, которая записывает строку в файл на что-то вроде этого:

myFile.Write(LPCTSTR(cS), cS.GetLength()*sizeof(TCHAR)); 

sizeof(TCHAR) даст другой номер, основанный на если вы строите для Unicode или MBCS. Это связано с тем, что TCHAR определяется как wchar_t для сборников Unicode, а также как char для сборки MBCS. Таким образом, умножение длины строки с размером TCHAR будет всегда равным количеству байтов, в которое состоит строка, независимо от того, строится ли для Unicode или нет.

Другие не отметить:

У тебя нет оснований называть GetBuffer() и ReleaseBuffer() здесь, вообще.

Этот пункт не является основным, но функция CFile::Write принимает первый аргумент const void *. Поэтому вы должны скорее отличить CString до LPCTSTR (который автоматически оценивается до LPCWSTR или LPCSTR на основе, если вы строите Unicode или MBCS).

Последнее: Хорошо обернуть строковые литералы макросом _T(), чтобы вы могли скомпилировать Unicode и MBCS, не изменяя свой код.

Применяя все изменения, весь ваш код будет выглядеть примерно так:

CString cS(_T("Hello")); 
myFile.Write(LPCTSTR(cS), cS.GetLength()*sizeof(TCHAR)); 
+0

Семантически, 'sizeof (TCHAR)' скорее должен быть 'sizeof (cS :: XCHAR)'. Это предопределенный тип символа для всех типов строк, полученных из 'CStringT'. Я также рекомендовал бы против явного литья. Оператор преобразования неявно вызывается. Если вы хотите быть явным, вы можете назвать его 'GetString()' member вместо этого. Это предотвращает непреднамеренное обращение оператора преобразования. – IInspectable

+0

@ Я не думаю, что вы можете набрать 'sizeof (cS :: XCHAR)' и скомпилировать его. Я думаю, вы, вероятно, имели в виду 'sizeof (CString :: XCHAR)', но это будет то же самое, что и 'sizeof (TCHAR)'. Также обратите внимание, что 'LPCTSTR' на самом деле является оператором: https://msdn.microsoft.com/en-us/library/aa300569(v=vs.60).aspx –

+0

*« Я думаю, вы, вероятно, имели в виду 'sizeof (CString :: XCHAR) ', но это будет то же самое, что и' sizeof (TCHAR) '." * - Это правда, они обозначают один и тот же тип. Однако существует семантическая разница: в то время как 'TCHAR' является просто несвязанным типом,' XCHAR' является типом, который используется во всей реализации CString.* «Также обратите внимание, что' LPCTSTR' на самом деле является оператором *. Именно поэтому я назвал его «оператором преобразования» * ранее. Он все еще неявно вызывается. Правильная ссылка на документацию - [здесь] (https://msdn.microsoft.com/en-us/library/sddk80xf.aspx#csimplestringt__operator_pcxstr). – IInspectable

0

Это потому, что вы компилируете с UNICODE, а CString - это строка с широкими символами, каждая из которых занимает два байта. То, что записывается в ваш файл, - это то, что вы видите как байтовый символ, за которым следует нулевой байт.

+3

Стоит отредактировать, чтобы явно указать, что 'GetLength' вернет число символов, а не количество байтов, и, следовательно, половина того, что требует' Write'. – user4581301

0

Я развиваю в MFC, Visual C++ 6.0 до Visual C++ 2005 около 4 лет профессионально, чтобы поддерживать приложения наших компаний.

В моих опытах и ​​то, что я знаю об объектах класса CString, они всегда NULL завершены. Это может привести к другому поведению, чем использование массива символов, но это не проблема выше.

Я считаю, что ваша проблема связана с буфером, который вы передаете в качестве аргумента. LPWSTR - это 32-разрядный указатель на строку из 16-разрядных символов в этом MSDN Reference.

Из чего я могу судить по тому, что вы опубликовали, вы выводите 16-битные символы Unicode и рассматриваете их как ANSI, поэтому это поведение ожидалось. Если бы вы открыли свой блокнот как Unicode, вы не увидели бы пробелы.

В качестве альтернативы, если вы создаете свой проект с использованием набора символов ANSI или конвертируете в ANSI перед записью в файл, пробелы должны исчезнуть при открытии вывода в блокноте.

0

попробовать это

TCHAR c[] = "Hello!"; 
int charCount = sizeof(c)/sizeof(c[0]); 
myFile.Write(c, charCount*sizeof(c[0])); 

Запись будет писать только число байтов, указанных. charCount будет таким же, как количество байтов для ASCII, но будет половину значения для UNICODE.

Попробуйте изменить код выше для вашего типа текста

https://msdn.microsoft.com/en-us/library/6337eske.aspx