用C 的名称重命名文件

Renaming a file with an en dash in the name in C++

本文关键字:重命名 文件      更新时间:2023-10-16

在我正在从事的项目中,我使用文件,我在继续之前检查它们是否存在。重命名,甚至可以使用文件路径中的" en Dash"的文件似乎不可能。

std::string _old = "D:\Folder\This – by ABC.txt";
std::rename(_old.c_str(), "New.txt");

在这里,_old变量被解释为d: folder this -abc.txt我尝试了

setlocale(LC_ALL, "");
//and
setlocale(LC_ALL, "C");
//or    
setlocale(LC_ALL, "en_US.UTF-8");

但是它们都没有起作用。.

这取决于操作系统。在Linux文件名中是简单的字节数组:忘记编码,只重命名文件。

,但看来您正在使用Windows,而文件名实际上是一个包含16位字符的null终止字符串。在这种情况下,最好的方法是使用wstring而不是用编码混乱。

不要尝试编写独立的代码来解决平台特定问题。Windows使用Unicode进行文件名,因此您必须编写特定于平台的代码,而不是使用标准函数rename

只需写L"D:\Folder\This u2013 by ABC.txt"并调用_wrename

Windows ANSI Western编码具有Unicode N-Dash,U 2013,;,作为代码点150(十进制)。当您将其输出使用Active Code Page 437(原始IBM PC字符集)或兼容的控制台时,则将其解释为An“ rdquo;。因此,您的字符串文字中有正确的CodePage 1252字符,要么是因为

  • 您正在使用Visual C ,默认为Windows ANSI编码编码狭窄的字符串文字,或

  • 您正在使用旧版本的G ,该版本不进行标准规定的转换和检查,但只能通过其机械直接传递狭窄的字符字节,并且您的源代码被编码为Windows ANSI Western(或兼容)或

  • 我没想到的东西。

对于前两个可能性中的任何一个

';      rename调用将有效

我测试了它确实与Visual C 一起使用。我周围没有G 的旧版本,但是我测试了它与版本5.1一起工作。也就是说,我测试了该文件确实将其重命名为New.txt

// Source encoding: UTF-8
// Execution character set: Windows ANSI Western a.k.a. codepage 1252.
#include <stdio.h>      // rename
#include <stdlib.h>     // EXIT_SUCCESS, EXIT_FAILURE
#include <string>       // std::string
using namespace std;
auto main()
    -> int
{
    string const a = ".\This – by ABC.txt";    // Literal encoded as CP 1252.
    return rename( a.c_str(), "New.txt" ) == 0? EXIT_SUCCESS : EXIT_FAILURE;
}

示例:

[c: my  forums  so  265]&gt; dir/b *.txt 文件未找到[c: my  forums  so  265]&gt; g    r.cpp -fexec -charset = cp1252 [c: my  forums  so  265]&gt; type nul&gt;" this  -  by abc.txt" [c: my  forums  so  265]&gt;运行退出代码0[c: my  forums  so  265]&gt; dir/b *.txt new.txt[c: my  forums  so  265]&gt;_

&hellip;其中run只是报告退出代码的批处理文件。


如果您的Windows ANSI CodePage不是CodePage 1252,则需要使用特定的Windows ANSI CodePage。

您可以通过GetACP API函数检查Windows ANSI CodePage,或者通过此命令:

[c: my  forums  so  265]&gt; WMIC OS获取代码集/值|查找" =" 代码= 1252[c: my  forums  so  265]&gt;_

如果该代码epage支持n-dash字符,则代码将起作用。

此编码模型基于每个相关主要语言环境(包括字符编码)的一个版本。


一种替代方法是在Unicode中完成所有操作。这可以通过Boost文件系统进行便捷完成,该系统将在C 17中的标准库中采用。或者,您可以使用Windows API或Windows中标准库的标准扩展名,即_rename

使用Visual C 2015的实验文件系统模块的示例:

// Source encoding: UTF-8
// Execution character set: irrelevant (everything's done in Unicode).
#include <stdlib.h>     // EXIT_SUCCESS, EXIT_FAILURE
#include <filesystem>   // In C++17 and later, or Visual C++ 2015 and later.
using namespace std::tr2::sys;
auto main()
    -> int
{
    path const old_path = L".\This – by ABC.txt";    // Literal encoded as wide string.
    path const new_path = L"New.txt";
    try
    {
        rename( old_path, new_path );
        return EXIT_SUCCESS;
    }
    catch( ... )
    {}
    return EXIT_FAILURE;
}

要适当地对可移植代码执行此操作,您可以使用Boost,也可以创建一个使用任何可用实现的包装标头。

它确实取决于平台,unicode是头痛。取决于您使用的编译器。对于来自MS(VS2010或以上的VS2010)的较旧元素,您需要使用MSDN中描述的API。此测试示例可以使用您的名称创建文件,然后将其重命名

// #define _UNICODE // might be defined in project
#include <string>
#include <tchar.h>
#include <windows.h>
using namespace std;
// Convert a wide Unicode string to an UTF8 string
std::string utf8_encode(const std::wstring &wstr)
{
    if( wstr.empty() ) return std::string();
    int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
    std::string strTo( size_needed, 0 );
    WideCharToMultiByte                  (CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
    return strTo;
}
// Convert an UTF8 string to a wide Unicode String
std::wstring utf8_decode(const std::string &str)
{
    if( str.empty() ) return std::wstring();
    int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
    std::wstring wstrTo( size_needed, 0 );
    MultiByteToWideChar                  (CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
    return wstrTo;
}
int _tmain(int argc, _TCHAR* argv[] ) {
    std::string pFileName = "C:\This xe2x80x93 by ABC.txt";
    std::wstring pwsFileName = utf8_decode(pFileName);
    // can use CreateFile id instead
    HANDLE hf = CreateFileW( pwsFileName.c_str() ,
                      GENERIC_READ | GENERIC_WRITE,
                      0,
                      0,
                      CREATE_NEW,
                      FILE_ATTRIBUTE_NORMAL,
                      0);
    CloseHandle(hf);
    MoveFileW(utf8_decode("C:\This xe2x80x93 by ABC.txt").c_str(), utf8_decode("C:\This xe2x80x93 by ABC 2.txt").c_str());
}

这些帮助者仍然存在问题,因此您可以将一个终止的字符串终止。

std::string utf8_encode(const std::wstring &wstr)
{
    std::string strTo;
    char *szTo = new char[wstr.length() + 1];
    szTo[wstr.size()] = '';
    WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, szTo, (int)wstr.length(), NULL, NULL);
    strTo = szTo;
    delete[] szTo;
    return strTo;
}

// Convert an UTF8 string to a wide Unicode String
std::wstring utf8_decode(const std::string &str)
{
    std::wstring wstrTo;
    wchar_t *wszTo = new wchar_t[str.length() + 1];
    wszTo[str.size()] = L'';
    MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, wszTo, (int)str.length());
    wstrTo = wszTo;
    delete[] wszTo;
    return wstrTo;
}

一个具有转换字符大小的问题。.致电0,以0,因为目标缓冲区的大小允许获得转换所需的字符大小。然后,它将返回目标缓冲区大小所需的字节数。所有这些与代码的杂耍都解释了为什么像QT这样的框架变得如此复杂的代码以支持基于Unicode的文件系统。实际上,摆脱所有可能的错误的最佳成本效益方法是使用这种框架。

vs2015

std::string _old = u8"D:\Folder\This xe2x80x93 by ABC.txt"s;

根据他们的文档。我无法检查一个。

mingw。

std::string _old = u8"D:\Folder\This xe2x80x93 by ABC.txt";
std::cout << _old.data();

输出包含正确的文件名...但是对于文件API,您仍然需要做正确的转换