为什么 std::fopen 和 std::filebuf::open 在 Windows 上修剪尾随空格字符?
当我尝试将一段 C++ 代码从 MSWindows 移植到 Linux (Mint10) 时,我偶然发现了一个奇怪的问题。我发现硬编码文件名中有一个小拼写错误:尾随空格字符(\x20)。
该代码在Windows(Windows Vista/7)下运行得很好,但在Linux下处理错误的文件名时遇到了麻烦。我发现 std::filebuf::open
和 std::fopen
(以及 boost::filesystem::filebuf
)都允许尾随Windows 下文件名中的空格字符(我认为这是不正确的行为)。
我在Win7下使用MSVC2010和MinGW测试了以下代码:
# include <iostream>
# include <fstream>
# include <string>
# include <cstdlib>
const std::string filename = "Z:\\Path\\To\\A\\File " ; // one trailing space
int main(int, char * [])
{
std::cout << "Testing with file : \"" << filename << "\"" << std::endl ;
// Testing with std::filebuf::open
std::filebuf fb ;
fb.open(filename.c_str(), std::ios::in | std::ios::binary) ;
if( fb.is_open() )
{
std::cout << "Using std::filebuf : Opened" << std::endl ;
fb.close() ;
}
else
{
std::cout << "Using std::filebuf : Not opened" << std::endl ;
}
// Testing with std::fopen
std::FILE * fp = std::fopen(filename.c_str(), "rb") ;
if( fp )
{
std::cout << "Using std::fopen : Opened" << std::endl ;
std::fclose(fp) ;
}
else
{
std::cout << "Using std::fopen : Not opened" << std::endl ;
}
return 0 ;
}
我验证了硬盘上的文件名称中没有尾随空格字符。该文件在 Windows 上已成功打开,但如果文件名不完全匹配,则无法在 Linux 下访问该文件。
所以我有几个问题:
- 这是 Windows 下文件 API 的正常行为吗?还有其他问题吗?我用谷歌搜索但没有找到有关此案例的参考资料。 (也许我是一个糟糕的谷歌者:))
- 如何编写一个以严格的方式使用文件名工作的代码?在将文件名传递给某些文件函数之前始终修剪文件名并不是我的情况的解决方案;我当前的应用程序必须列出目录(使用boost::filesystem::directory_iterator),如果用户提供带有尾随空格字符的文件名(这种情况很少见,但在许多文件系统上是允许的),修剪文件名将破坏应用程序)。
感谢您的任何建议!
I stumbled on a strange problem when trying to port a piece of C++ code from MSWindows to linux (Mint10). I discovered that there was a little typo in a hard-coded filename : a trailing space char (\x20).
The code worked like a charm under Windows (Windows Vista/7), but it had trouble to deal with the erroneous filename under linux. I discovered that both std::filebuf::open
and std::fopen
(and also boost::filesystem::filebuf
) allow trailing space chars in filename under Windows (which I think is an incorrect behavior).
I tested the following code using MSVC2010 and MinGW under Win7 :
# include <iostream>
# include <fstream>
# include <string>
# include <cstdlib>
const std::string filename = "Z:\\Path\\To\\A\\File " ; // one trailing space
int main(int, char * [])
{
std::cout << "Testing with file : \"" << filename << "\"" << std::endl ;
// Testing with std::filebuf::open
std::filebuf fb ;
fb.open(filename.c_str(), std::ios::in | std::ios::binary) ;
if( fb.is_open() )
{
std::cout << "Using std::filebuf : Opened" << std::endl ;
fb.close() ;
}
else
{
std::cout << "Using std::filebuf : Not opened" << std::endl ;
}
// Testing with std::fopen
std::FILE * fp = std::fopen(filename.c_str(), "rb") ;
if( fp )
{
std::cout << "Using std::fopen : Opened" << std::endl ;
std::fclose(fp) ;
}
else
{
std::cout << "Using std::fopen : Not opened" << std::endl ;
}
return 0 ;
}
I verified that the file on the harddrive has no trailing space characters in the name. The file was successfully opened on Windows, but no luck to access it under linux if the filename isn't an exact match.
So I have a couple of questions :
- Is this a normal behavior of the file API under Windows ? And is there some other gotchas ? I googled but found no reference on this case. (Maybe I'm a bad googler :))
- How to write a code that works in a strict fashion with filenames ? Always trimming filenames before passing them to some file function isn't the solution for my case ; my current app have to list directories (using
boost::filesystem::directory_iterator
) and trimming filenames will break the app if the user provides filenames with trailing space chars (which is rare but allowed on many file systems).
Thanks for any advice !
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Windows 本身会去除文件名中的尾随空格,它与您用来打开文件的 C++ 函数无关。
以下是 Windows API 函数 CreateFile 中对此行为的一个引用:信息:不支持以空格或句点结尾的文件名
Windows itself will strip the trailing blanks from a filename, it has nothing to do with the C++ function you use to open the file.
Here's one reference to this behavior in the Windows API function CreateFile: INFO: Filenames Ending with Space or Period Not Supported