Ale*_*nko 0 c++ file-io createfile
我的方法中有这样的实现
std::string name2 = "D:\\Buffer\\Temp\\t_libpng" + std::to_string(i) + ".png";
Run Code Online (Sandbox Code Playgroud)
bool _write_png_file_cv2_(char const *filename,
int width,
int height,
int widthStep,
png_byte color_type,
png_byte bit_depth,
png_bytep *row_pointers)
{
// ...
hFile = CreateFile((LPCWSTR)filename, // Open Two.txt.
GENERIC_WRITE, // Open for writing
0, // Do not share
NULL, // No security
OPEN_ALWAYS, // Open or create
FILE_ATTRIBUTE_NORMAL, // Normal file
NULL); // No template file
if (hFile == INVALID_HANDLE_VALUE)
{
printf("ERROR:: Could not open file");
CloseHandle(hFile); // Close the first file.
return false;
}
DWORD dwBytesWritten;
//fclose(fp);
//writeSamsungToDisk(png->buffer,png->idx);
BOOL result = WriteFile(
hFile,
png->buffer,
png->idx,
&dwBytesWritten,
NULL);
CloseHandle(hFile);
// ...
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,文件名是D:\\Buffer\\Temp\\t_libpng0.png,buff 的大小是 8977。
if (hFile == INVALID_HANDLE_VALUE)我会看到我没有收到任何错误,对我来说这意味着我可以去目的地D:\\Buffer\\Temp并在那里找到我的文件,但什么也没有。OPEN_ALWAYS应该创建一个文件)。CloseHandle(hFile)并检查变量dwBytesWritten,我看到写入的字节数为 8977,完全相同。这里有什么问题?
CreateFile()是一个预处理器宏,根据是否定义映射到CreateFileW()(which requires wchar_t*) 或CreateFileA()(which takes char*) UNICODE。ClearlyUNICODE已在您的项目中定义,这就是为什么CreateFile()期望wchar_t*.
// winbase.h
WINBASEAPI
__out
HANDLE
WINAPI
CreateFileA(
__in LPCSTR lpFileName,
__in DWORD dwDesiredAccess,
__in DWORD dwShareMode,
__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
__in DWORD dwCreationDisposition,
__in DWORD dwFlagsAndAttributes,
__in_opt HANDLE hTemplateFile
);
WINBASEAPI
__out
HANDLE
WINAPI
CreateFileW(
__in LPCWSTR lpFileName,
__in DWORD dwDesiredAccess,
__in DWORD dwShareMode,
__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
__in DWORD dwCreationDisposition,
__in DWORD dwFlagsAndAttributes,
__in_opt HANDLE hTemplateFile
);
#ifdef UNICODE
#define CreateFile CreateFileW
#else
#define CreateFile CreateFileA
#endif // !UNICODE
Run Code Online (Sandbox Code Playgroud)
您正在将filename参数从char*to类型转换wchar_t*。铸造一个char*指针wchar_t*的,当你删除型铸造编译器会抱怨这样的事实在这种情况下是行不通的,因为显而易见的。类型转换所做的只是对编译器撒谎,告诉它指针指向wchar_t数据,而实际上它实际上指向的是char数据。
因此,当您有一个char*指向charstring的指针"D:\\Buffer\\Temp\\t_libpng0.png",并且您将该指针类型转换传递给 时CreateFileW(),该函数认为您传递的是一个双字节wchar_t字符串"??????????????":
注意字节不会改变,只是对它们的解释。这种不匹配通常被称为“mojibake”。
"??????????????"是一个完全有效的文件名的CreteFileW(),但它没有指定的目录,所以CreateFileW()将把字符串作为相对路径,并创建调用进程的该文件当前的工作目录。这就是为什么您的代码没有失败,但文件不在您期望的位置,或命名为您期望的内容。
因此,使用CreateFile()在这种情况下正确的宏,你就必须真正转变您的char数据,wchar_t使用数据MultiByteToWideChar()(或同等学历),例如:
// winbase.h
WINBASEAPI
__out
HANDLE
WINAPI
CreateFileA(
__in LPCSTR lpFileName,
__in DWORD dwDesiredAccess,
__in DWORD dwShareMode,
__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
__in DWORD dwCreationDisposition,
__in DWORD dwFlagsAndAttributes,
__in_opt HANDLE hTemplateFile
);
WINBASEAPI
__out
HANDLE
WINAPI
CreateFileW(
__in LPCWSTR lpFileName,
__in DWORD dwDesiredAccess,
__in DWORD dwShareMode,
__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
__in DWORD dwCreationDisposition,
__in DWORD dwFlagsAndAttributes,
__in_opt HANDLE hTemplateFile
);
#ifdef UNICODE
#define CreateFile CreateFileW
#else
#define CreateFile CreateFileA
#endif // !UNICODE
Run Code Online (Sandbox Code Playgroud)
或者,将filename参数从char*to更改wchar_t*为开头,然后更新调用者以使用std::wstring而不是std::string,例如:
#ifdef UNICODE
int len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
wchar_t *w_filename = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, filename, -1, w_filename, len);
hFile = CreateFile(w_filename, ...);
// better:
// hFile = CreateFileW(w_filename, ...);
delete[] w_filename;
#else
hFile = CreateFile(filename, ...);
// better:
// hFile = CreateFileA(filename, ...);
#endif
Run Code Online (Sandbox Code Playgroud)
std::wstring name2 = L"D:\\Buffer\\Temp\\t_libpng" + std::to_wstring(i) + L".png";
_write_png_file_cv2_(name2.c_str(), ...);
Run Code Online (Sandbox Code Playgroud)
否则,如果您想继续使用std::string/char*那么您可以直接调用CreateFileA(),并让它在内部为您处理转换:
hFile = CreateFileA(filename, ...);
Run Code Online (Sandbox Code Playgroud)
一个很好的经验法则 - 当你TCHAR不在代码中使用类型时,你应该远离使用任何TCHAR基于函数的宏。使用特定于您正在使用的实际数据类型的函数。例如,在这种情况下,通过调用CreateFileA()forchar*和CreateFileW()for wchar_t*,根本不是CreateFile()。