提问人:Dmitriano 提问时间:10/6/2022 更新时间:10/6/2022 访问量:121
使用 Win32 API 函数 ReadFile 和 WriteFile 将代码迁移到 Linux 的正确方法
The right way to migrate a code using Win32 API functions ReadFile and WriteFile to Linux
问:
我有一个使用 Win32 API 函数的自定义流实现,例如 、 。此外,流实现和函数不受 (它刷新其内部缓冲区,但不刷新操作系统缓冲区):::CreateFile2
::ReadFile
::WriteFile
Flush
Truncate
std::fstream
flush()
class WinStream : public IoStream
{
public:
size_t Read(uint8_t* buffer, size_t count) override
{
const DWORD nNumberOfBytesToRead = static_cast<DWORD>(count);
assert(nNumberOfBytesToRead == count);
DWORD NumberOfBytesRead = 0;
Check(::ReadFile(m_hFile, buffer, nNumberOfBytesToRead, &NumberOfBytesRead, NULL) != FALSE);
return NumberOfBytesRead;
}
void Write(const uint8_t* buffer, size_t count) override
{
const DWORD nNumberOfBytesToWrite = static_cast<DWORD>(count);
assert(nNumberOfBytesToWrite == count);
DWORD NumberOfBytesWritten = 0;
if (::WriteFile(m_hFile, buffer, nNumberOfBytesToWrite, &NumberOfBytesWritten, NULL) == FALSE)
{
throw IoError(format()
<< _T("::WriteFile failed. This may indicate that the disk is full. Win32 Error: ")
<< ::GetLastError());
}
if (nNumberOfBytesToWrite != NumberOfBytesWritten)
{
throw IoError(format() << _T("Requested ") << nNumberOfBytesToWrite
<< _T(" bytes, but actually written ") << NumberOfBytesWritten << _T("."));
}
bool End() override
{
return GetFileSizeHelper() == GetFilePointerHelper();
}
void Seek(std::size_t pos, bool begin = true) override
{
LARGE_INTEGER li;
li.QuadPart = pos;
Check(::SetFilePointerEx(m_hFile, li, NULL, begin ? FILE_BEGIN : FILE_END) != INVALID_SET_FILE_POINTER);
}
void Move(std::ptrdiff_t offset) override
{
LARGE_INTEGER li;
li.QuadPart = offset;
Check(::SetFilePointerEx(m_hFile, li, NULL, FILE_CURRENT) != INVALID_SET_FILE_POINTER);
}
void Flush() override
{
Check(::FlushFileBuffers(m_hFile) != FALSE);
}
void Truncate() override
{
Check(::SetEndOfFile(m_hFile) != FALSE);
}
private:
void Check(bool success)
{
if (!success)
{
throw Win32Exception();
}
}
LONGLONG GetFileSizeHelper()
{
LARGE_INTEGER li;
li.QuadPart = 0;
Check(::GetFileSizeEx(m_hFile, &li) != FALSE);
return li.QuadPart;
}
LONGLONG GetFilePointerHelper()
{
LARGE_INTEGER liOfs = { 0 };
LARGE_INTEGER liNew = { 0 };
Check(::SetFilePointerEx(m_hFile, liOfs, &liNew, FILE_CURRENT) != INVALID_SET_FILE_POINTER);
return liNew.QuadPart;
}
FileHandle m_hFile;
}
inline UniqueFileHandle CreateUniqueFile(const String& file_name)
{
HANDLE hFile = ::CreateFile2(
file_name.c_str(),
GENERIC_READ | GENERIC_WRITE,
0, //FILE_SHARE_READ | FILE_SHARE_WRITE,
OPEN_ALWAYS,
NULL //&extendedParams
);
if (hFile == INVALID_HANDLE_VALUE)
{
DWORD dw_err = ::GetLastError();
throw IoError(format() << _T("Cannot open file ')" << file_name << "' for updating, error = " << dw_err));
}
return hFile;
}
将此代码迁移到 Linux 的正确(或现代)方法是什么?那么 Android、MacOS 和 iOS 呢?
它应该使用非缓冲读/写函数。
答:
0赞
cs1349459
10/6/2022
#1
正如 Homer512 所说,您应该使用 POSIX 文件函数,例如 、 、 和 。您可以在此处找到这些函数的参考。fopen
fwrite
fclose
fread
我个人更喜欢让代码在许多系统上工作,即使用预处理器指令,并为每个操作系统提供代码。可以在此处找到 os 指令的完整列表。
若要分离操作系统的代码,可以执行如下操作:
#ifdef _WIN32
//Windows code here
#elifdef __APPLE__
//MacOS code here
#elifdef __linux__
//Linux code here
#endif
然后,您可以使用一组特定的函数,例如打开文件、写入文件,然后使用其特定方式在不同的系统上定义它们。您也可以轻松地将其扩展到其他操作系统。
评论
open
write
read
fsync
FILE
fileno(FILE*)