65.9K
CodeProject 正在变化。 阅读更多。
Home

处理句柄的实用指南

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.73/5 (23投票s)

2001 年 4 月 5 日

5分钟阅读

viewsIcon

294862

文件句柄及其与 File *、CFile、CStdioFile 等的关系之奥秘。

免责声明

我正在撰写这篇技术文章。但是,其中已包含的信息非常有价值,以至于我决定将其发布出来,尽管我只涵盖了句柄的一小部分。在接下来的几个月里,我将对其进行改进。请耐心等待;更多内容即将到来。

文件句柄

我有一个 FILE *。或者我有一个 CFileCStdioFile。它的句柄是什么?它是什么句柄?

在应用程序级别,文件句柄有几种表示方式。有 C 库提供的文件句柄,有 FILE * 对象,还有操作系统文件句柄。它们都是可以互换的,但前提是你知道你在做什么。 

它们**并非**在瞬间就可以随意互换,因为存在诸如缓冲等问题。因此,如果您访问一个 FILE * 并获取底层操作系统句柄,然后执行 WriteFile,您可能会得到一个严重损坏的文件,因为 FILE * 对象正在管理缓冲数据。因此,除非您了解如何刷新缓冲区并保持文件内容和位置的各种文件句柄图像的一致性,否则您将陷入严重困境。

更典型的情况是,您有一个新的、刚打开的句柄,想将其与更适合您任务的表示形式关联起来。例如,C 库函数 fopen 在处理文件共享方面做得非常糟糕,而文件共享的概念在最初指定它的 Unix 操作系统中是不存在的。您想使用完整的 Win32 文件共享,但又不想进行原始的 WriteFile 操作。也许您不能,因为您正在将某些内容回溯到现有的、可能跨操作系统可移植的源代码集中,并且您正在编写特定于操作系统的模块。因此,您可以从 CreateFile 获取一个真正的 Win32 HANDLE,并希望将其与 FILE * 关联起来,以便现在可以方便地使用它。甚至可以将其与 C++ fstream 关联起来。请继续阅读!

C 库“句柄”是索引 C 运行时库中表的较小整数。传统上,C 库将同时打开的文件数量限制在非常有限的句柄数,例如 16 个。在 Win32 中,这不再是问题。Win32 中的 C 库现在支持多达 2048 个低级句柄。默认情况下,最多允许 512 个 FILE * 对象,尽管您可以通过调用 _setmaxstdio 轻松地将此限制更改为最多 2048 个。

如果您在下表中找不到所需的转换,您将需要组合使用这些转换。例如,要将 HANDLE 转换为 fstream,您需要执行类似的操作:

HANDLE h = ::CreateFile(...);
fstream f;
f.attach(_open_osfhandle(h));

直接文件句柄转换摘要

来源 改为 不如使用:
HANDLE Win32

CreateFile

C 库句柄 _open_osfhandle
CFile CFile::CFile
C 库句柄 <io.h>

_open
_sopen

HANDLE _get_osfhandle
FILE * _fdopen
fstream fstream::fstream
fstream::attach
FILE * <stdio.h>

fopen

C 库句柄 _fileno
CStdioFile CStdioFile::CStdioFile
CFile MFC HANDLE m_hFile 数据成员
CStdioFile MFC FILE * m_pStream 数据成员
stdxxx Win32 HANDLE GetStdHandle
fstream C++ 库 C 库句柄 fstream 的 .fd 方法


Win32 HANDLE 到 C 库句柄

<io.h>
int _open_osfhandle(long oshandle, int flags)

此函数接受一个 HANDLE 值并返回一个可以与 C 库交互的小整数。flags 值包括 O_APPENDO_RDONLYO_TEXT。请注意,此原型假定 longHANDLE 大小相同,您需要进行类型转换才能通过编译器,例如:

int h = _open_osfhandle((long) myhandle, 0);

目前尚不清楚微软在 Win64 中将如何处理此库调用,因为我认为 Win64 中的句柄将是 64 位宽。

返回索引


C 库句柄到 FILE *

给定一个 C 库文件句柄,您可以通过调用函数 _fdopen,传入 C 库文件句柄并返回 FILE * 来将其转换为 FILE*

<stdio.h><code>
int _fdopen(int filehandle, const char * mode)

其中 mode  是您可以提供给 fopen 的任何模式值,例如 "r""rw""w" 等。

返回索引


FILE * 到 C 库句柄

给定一个 FILE * 对象,您可以使用 _fileno 获取底层 C 库句柄。

<stdio.h>
<code>int _fileno(FILE * f)

返回索引


C 库句柄到 Win32 句柄

<io.h>
long _get_osfhandle(int filehandle)

此函数接受一个 C 库文件句柄并返回底层的 Win32 HANDLE

返回索引


CFile 到 HANDLE

CFile 对象之下是系统文件句柄。有时。可能。在原始的 CFile 中,m_hfile 成员是系统文件句柄。但是,微软警告说这在派生类中可能会改变。

返回索引


HANDLE 到 CFile

要将 CFile 对象与操作系统文件句柄关联起来,请使用以下形式的 CFile 构造函数:

CFile::CFile(HANDLE h)

您是在堆栈变量中执行此操作还是使用堆分配取决于您的应用程序的性质。

CFile file(myhandle);

CFile * file = new CFile(myhandle);

返回索引


CStdioFile 到 FILE *

CStdioFilem_pStream 成员是对其底层 FILE * 对象的引用。

返回索引


FILE * 到 CStdioFile

要将 CStdioFile 对象与操作系统文件句柄关联起来,请使用以下形式的 CStdioFile 构造函数:

CStdioFile::CStdioFile(FILE * f)

您是在堆栈变量中执行此操作还是使用堆分配取决于您的应用程序的性质。

<code>CStdioFile file(myfile);

CStdioFile * file = new CStdioFile(myfile);

返回索引


stdxxx 到 HANDLE

如果您需要 stdinstdoutstderr 的句柄,而又不使用 stdio.h 库,您可以使用 API 调用 GetStdHandle,指定常量 STD_INPUT_HANDLESTD_OUTPUT_HANDLESTD_ERROR_HANDLE 之一。这些将返回一个 HANDLE  值,可用于 ReadFileWriteFile 或与上述任何函数一起使用。

返回索引


C 库句柄到 fstream

如果您有一个 C 库句柄(来自 _open_sopen 的小整数)并需要一个 C++ fstream 类对象,请查看 fstream 构造函数。一种形式接受 C 文件描述符:

fstream(filedesc fd)

您还可以使用 fstream::attach 方法将文件描述符附加到现有的 fstream

fstream f; 
f.attach(fd);

要使此功能正常工作,不能有文件描述符已附加到 fstream

返回索引


fstream 到 C 库句柄

要从 fstream 获取底层 C 库句柄,请使用 .fd 方法。

fstream f;
f.attach(fd)
ASSERT(fd == f.fd()) 

返回索引

可继承句柄

好的,很快就会有……

其他句柄

同样……

发送邮件至newcomer@flounder.com提出关于本文的问题或评论。
版权所有 © 1999[]保留所有权利
www.flounder.com/mvp_tips.htm
© . All rights reserved.