使用 Write 成员将 CString 写入 CFile 时每个字符后的 Null
Posted
技术标签:
【中文标题】使用 Write 成员将 CString 写入 CFile 时每个字符后的 Null【英文标题】:Nulls after each character when writing CString to CFile using Write member 【发布时间】:2016-11-17 23:54:02 【问题描述】:我目前正在研究 MFC 库 CFile 类,但在使用 Write 方法将数据写入文件时遇到问题。当我将 char 数组作为参数传递时,它工作得很好:
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();
但是输出和上面一样。什么可能导致这种转换?是否因为文本存储在宽字符中而发生?
【问题讨论】:
使用CStringA
而不是CString
。 ASCII 范围内的宽字符由一个字节 ASCII 和一个空字节组成。
【参考方案1】:
问题:
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
(根据您是使用Unicode 还是MBCS 构建,它会自动评估为LPCWSTR
或LPCSTR
)。
最后一件事:最好用 _T()
宏包装字符串文字,这样您就可以针对 Unicode 和 MBCS 进行编译,而无需更改代码。
应用所有更改,您的整个代码将如下所示:
CString cS(_T("Hello"));
myFile.Write(LPCTSTR(cS), cS.GetLength()*sizeof(TCHAR));
【讨论】:
语义上,sizeof(TCHAR)
应该是sizeof(cS::XCHAR)
。这是所有CStringT
派生字符串类型的预定义字符类型。我还建议不要显式转换。隐式调用转换运算符。如果你想明确一点,你可以把它称为GetString()
成员。这样做可以防止无意中调用转换运算符。
@IInspectable 我不认为你可以输入sizeof(cS::XCHAR)
并让它编译。我想你可能指的是sizeof(CString::XCHAR)
,但这与sizeof(TCHAR)
完全相同。另外,请注意LPCTSTR
实际上是一个运算符:msdn.microsoft.com/en-us/library/aa300569(v=vs.60).aspx
“我想你的意思可能是sizeof(CString::XCHAR)
,但这与sizeof(TCHAR)
完全一样。” - 没错,它们指定了相同的类型。但是,存在语义上的区别:TCHAR
只是一个不相关的类型,XCHAR
是整个CString
实现中使用的类型。 “另外,请注意LPCTSTR
实际上是一个运算符” - 这就是我之前将其称为“转换运算符” 的原因。它仍然被隐式调用。文档的正确链接是here。
“我不认为你可以输入 sizeof(cS::XCHAR)
并让它编译。” - 正确,我的意思是写 sizeof( decltype( cS )::XCHAR )
。对于任何给定的CString
实例,无论项目设置如何,总是 返回字符代码单元的正确大小。这很重要,因为您可以在 Unicode 项目中使用 CStringA
,或在 MBCS 项目中使用 CStringW
,因此 sizeof( TCHAR )
会产生错误的值。
@IInspectable 太糟糕了CString
没有定义一个等于sizeof(XCHAR)
的常量成员,它会让这变得容易得多。【参考方案2】:
那是因为你在编译时定义了UNICODE
,而CString
是一个宽字符字符串,每个字符占用两个字节。写入文件的内容是您所看到的字符字节,后跟零字节。
【讨论】:
值得编辑以明确声明GetLength
将返回字符数,而不是字节数,因此是 Write
要求的一半。【参考方案3】:
我已经在 MFC、Visual C++ 6.0 到 Visual C++ 2005 中进行了大约 4 年的专业开发,以支持我们公司的应用程序。
根据我的经验和我对CString
类对象的了解,它们总是NULL
终止。这可能会导致与使用字符数组不同的行为,但不是上述问题。
我相信您的问题与您作为参数传入的缓冲区有关。 LPWSTR
是一个 32 位指针,指向每个 MSDN Reference 的 16 位字符的字符串。
根据您发布的内容,据我所知,您正在输出 16 位 Unicode
字符并将它们视为 ANSI
因此这种行为是可以预料的。如果您以Unicode
的身份打开记事本文件,您将看不到空格。
或者,如果您使用 ANSI
字符集构建项目,或在写入文件之前转换为 ANSI
,则在记事本中打开输出时空格应该会消失。
【讨论】:
【参考方案4】:试试这个
TCHAR c[] = "Hello!";
int charCount = sizeof(c) / sizeof(c[0]);
myFile.Write(c, charCount*sizeof(c[0]));
Write 将只写入指定的字节数。 charCount 将与 ASCII 的字节数相同,但将是 UNICODE 值的一半。
尝试根据您的文本类型更改上述代码
https://msdn.microsoft.com/en-us/library/6337eske.aspx
【讨论】:
以上是关于使用 Write 成员将 CString 写入 CFile 时每个字符后的 Null的主要内容,如果未能解决你的问题,请参考以下文章
R语言write函数:使用write函数将数据写入RStudio控制台write函数将数据写入新的Rstudio窗口(启动新的窗口)