分类目录归档:技术文献

Linux_Ext分区超级块结构

Chkdsk的新增开关 /C 和 /I 说明

 

Chkdsk.exe 是 CHKDSK 程序的命令行界面,该程序用于验证文件系统的逻辑完整性。如果 CHKDSK 在文件系统数据中发现存在逻辑不一致性,CHKDSK 将执行可修复该文件系统数据的操作(前提是这些数据未处于只读模式)。

/C 和 /I 开关仅对使用 NTFS 文件系统格式化的驱动器有效。这两个新的开关都指示 CHKDSK 例程跳过某些 CHKDSK 原本要执行以验证 NTFS 数据结构完整性的操作。

如果联机运行 CHKDSK,则实际执行验证的代码位于实用程序 DLL(例如 Untfs.dll 和 Ufat.dll)中。CHKDSK 调用的验证例程与通过 Windows 资源管理器或磁盘管理图形用户界面验证卷时所运行的例程相同。

但是,如果将 CHKDSK 计划为在计算机重新启动时运行,则包含验证代码的二进制模块为 Autochk.exe,它是一个 Windows 固有程序。由于 Autochk.exe 在计算机启动序列中靠前的位置运行,Autochk.exe 不具有虚拟内存或其他 Win32 服务的优点。

Autochk.exe 与 Chkdsk.exe 实用程序 DLL 生成相同种类的文本输出。Autochk.exe 在启动过程中显示这些文本输出,并在应用程序事件日志中记录事件。所记录的事件信息中包含事件日志的数据缓冲区所能容纳的最大数量的文本输出。

由于 Autochk.exe 和 Chkdsk.exe 实用程序 DLL 中的验证代码都基于相同的源代码,因此本文的其余部分将使用术语“CHKDSK”来统称 Autochk.exe 和 Chkdsk.exe。与此类似,由于本文仅讨论那些与 NTFS 卷有关的 CHKDSK 更改,因此,任何“CHKDSK 如何如何”的语句的意思都是“CHKDSK 在 NTFS 卷上运行时如何如何”。

请注意,如果您使用 /C 和 /I 开关,则即使运行了 CHKDSK,卷仍可能是损坏的。因此,建议您仅在必须将停机时间降至最短的情况下才使用这些开关。这些开关适用于以下场合:必须在特别大的卷上运行 CHKDSK,并且需要灵活地管理所造成的停机时间。

要了解何时适于使用 /C 和 /I 开关,您需要对某些内部的 NTFS 数据结构、可能发生的损坏的种类、CHKDSK 在验证卷时采取的操作以及回避 CHKDSK 的常规验证步骤可能有哪些后果等有一些基本的了解。

了解 CHKDSK 所采取的操作


CHKDSK 的活动分为三个主要阶段(在这三个阶段中,CHKDSK 将检查卷上的所有元数据),另外还有一个可选的第四阶段。

元数据是“有关数据的数据”。元数据是文件系统的“系统开销”,它跟踪有关所有在卷上存储的文件的信息。元数据包括有关以下方面的信息:给定文件的数据由哪些分配单元组成、哪些分配单元是可用的以及哪些分配单元包含坏扇区等。另一方面,文件包含的数据称为“用户数据”。NTFS 通过使用事务日志来保护它的元数据。用户数据没有以这种方式进行保护。

阶段 1:检查文件


在第一个阶段,CHKDSK 会显示一条消息,通知您 CHKDSK 正在验证文件,同时还显示已完成的验证任务的百分比(范围为从 0% 到 100%)。在此阶段中,CHKDSK 将检查卷的主文件表 (MFT) 中的各个文件记录段。

MFT 中的特定文件记录段唯一地标识 NTFS 卷上的各个文件和目录。CHKDSK 在此阶段显示的“已完成百分比”是 CHKDSK 已验证的 MFT 的百分比。在此阶段中,CHKDSK 将检查各个文件记录段的内部一致性,并生成两个位图,一个表示正在使用的文件记录段,另一个表示卷上正在使用的簇。

在此阶段结束时,CHKDSK 将会识别 MFT 内部和整个卷上的已用空间和可用空间。NTFS 在其自身的位图中跟踪这些信息,该位图存储在磁盘上。CHKDSK 将它的结果与 NTFS 保持的位图进行比较。如果存在差异,将在 CHKDSK 输出中记录这些差异。例如,如果发现正在使用的文件记录段损坏,则在 CHKDSK 位图中,与该文件记录段相关联的磁盘簇将被标记为“可用”,但在 NTFS 位图中,它将被标记为“使用中”。

阶段 2:检查索引


在第二个阶段,CHKDSK 会显示一条消息,通知您 CHKDSK 正在验证索引,同时还显示已完成的验证任务的百分比(范围为从 0% 到 100%)。在此阶段中,CHKDSK 将检查卷上的各个索引。

索引实际上就是 NTFS 目录。在此阶段中,CHKDSK 显示的“已完成百分比”是已检查的卷目录总数的百分比。在此阶段中,CHKDSK 将检查卷上的各个目录,检查内部一致性,并验证 MFT 中的文件记录段所代表的每个文件和目录都至少由一个目录引用。CHKDSK 确认目录中引用的每个文件或子目录都实际作为有效的文件记录段存在于 MFT 中,并且还检查是否存在循环目录引用。最后,CHKDSK 将确认在文件的目录项中,这些文件的时间戳和文件大小信息都是最新的。

在此阶段结束时,CHKDSK 将确保没有“孤立”的文件,并且所有目录项都用于合法的文件。孤立文件是指存在该文件的合法文件记录段,但该文件却没有列在任何目录中。如果相应的目录仍存在,则孤立文件通常可以恢复到正确的目录中。如果正确的目录已不存在,CHKDSK 将在根目录中创建一个目录,并将文件放入该目录中。如果 CHKDSK 发现不再使用的文件记录段的目录项,或者虽然仍在使用但并不与目录中列出的文件相对应的文件记录段的目录项,CHKDSK 将直接删除该文件记录段的目录项。

阶段 3:检查安全描述符


在第三个阶段,CHKDSK 会显示一条消息,通知您 CHKDSK 正在验证安全描述符,同时还显示已完成的验证任务的百分比(范围为从 0% 到 100%)。在此阶段中,CHKDSK 将检查与卷上的文件或目录相关联的每个安全描述符。

安全描述符包含有关下列方面的信息:文件或目录的所有权、文件或目录的 NTFS 权限以及文件或目录的审核。在此阶段中,CHKDSK 显示的“已完成百分比”是卷上已检查的文件和目录的百分比。CHKDSK 将验证各个安全描述符的结构是否正常,并验证该结构的内部一致性。CHKDSK 并不验证列出的用户或组实际上是否存在,也不验证所赋予的权限是否适当。

阶段 4:检查扇区


如果 /R 开关生效,CHKDSK 将运行第四个阶段,以便在卷的可用空间中查找坏扇区。CHKDSK 将尝试读取卷上的每个扇区,以确认该扇区是否可用。即使不使用 /R 开关,CHKDSK 也总是读取与元数据相关联的扇区。如果指定了 /R 开关,将在 CHKDSK 的较早阶段读取与用户数据关联的扇区。

当 CHKDSK 找到不可读的扇区时,NTFS 会将包含该扇区的簇加入它的坏簇列表中。如果坏扇区正在使用,CHKDSK 将分配一个新的簇,以完成该坏簇的工作。如果您使用的是容错磁盘,NTFS 将恢复坏簇的数据,并将这些数据写入新分配的簇中。否则,新的簇中将填充某种模式的 0xFF 字节。

如果 NTFS 在正常运行过程中遇到不可读的扇区,NTFS 将以与运行 CHKDSK 时相同的方式重新映射这些扇区。因此,通常无须使用 /R 开关。但是,如果怀疑磁盘可能有坏扇区,则使用 /R 开关就是一个扫描整个卷的简便办法。

了解 CHKDSK 的时间要求


前面对 CHKDSK 的各个运行阶段的说明只是粗略概述了 CHKDSK 为验证 NTFS 卷的完整性而执行的最重要任务。CHKDSK 还在各个阶段中执行许多额外的特定检查,并在各个阶段之间执行几种快速检查。但是,即使是这样的粗略概述也能够提供一些基础知识,以便我们开始讨论影响 CHKDSK 运行所需时间的可变因素,以及讨论 Windows XP 中可以使用的新增 /C 和 /I 开关的影响。

可变因素 1:“索引”阶段


在运行 CHKDSK 的第一和第三阶段(检查文件和检查安全描述符),“已完成百分比”指示器的进度相对比较平滑。虽然未使用的文件记录段需要的处理时间的确较少,而大型安全描述符的确需要较多的处理时间,但是总体说来“已完成百分比”相当准确地反映了该阶段所需的实际时间。

不过,这一百分比/时间关系却未必适用于第二阶段,也就是 CHKDSK 检查索引(NTFS 目录)的那个阶段。处理目录所需的时间与该目录中包含的文件和子目录的数量密切相关,但是在该阶段中,“已完成百分比”仅与 CHKDSK 必须检查的目录数量有关。并没有针对某些特定操作(例如,处理包含数量巨大的文件和子目录的目录)所需的时间进行调整。除非卷上的目录都包含大致相同数量的文件,否则该阶段中显示的“已完成百分比”将不会可靠地反映第二阶段所需的实际时间。

更坏的情况是您可能陷入意外的 CHKDSK 过程,这时 CHKDSK 的第二阶段通常是需时最长的阶段。

可变因素 2:卷的情况


许多与卷的状态有关的因素都会影响 CHKDSK 运行所需的时间。用于预测在给定卷上运行 CHKDSK 所需时间的公式必须考虑文件和目录的数目、卷的总体碎片化程度(特别是 MTF 的碎片化程度)、文件名的格式(长名称、8.3 格式名称或混合型名称)以及 CHKDSK 必须修复的实际损坏量等可变因素。

可变因素 3:硬件问题


硬件问题也会影响 CHKDSK 运行所需的时间。可变因素包括可用内存的数量、CPU 速度、磁盘速度等。

可变因素 4:CHKDSK 设置


如果不使用 /R 开关,则给定硬件平台上与时间最密切的因素是该卷上的文件和目录的数量,而不是卷的绝对大小。

例如,如果不使用 /R 开关,则对于仅包含一个或两个大型数据库文件的 50 GB 卷,CHKDSK 的运行可能只需要几秒钟。如果使用 /R 开关,CHKDSK 将必须读取并验证卷上的每个扇区,对于大型卷而言,这会显著增加运行所需的时间。另一方面,如果一个相对较小的卷包含几十万甚至几百万个小文件,则运行 CHKDSK 可能需要数小时,无论您是否指定 /R 开关。

预测 CHKDSK 的时间要求


如上所述,运行 CHKDSK 所需的时间从几秒到几天不等,这要由您的具体情况决定。预测对给定卷运行 CHKDSK 所需时间的最好办法是:在系统利用率较低的时段,以只读模式实际进行一次测试运行。

但是,出于以下原因,必须谨慎使用此方法:

·         在只读模式下,如果在较早阶段中遇到错误,CHKDSK 会在完成所有三个阶段之前退出,并很可能误报错误。例如,如果 NTFS 恰好在 CHKDSK 检查磁盘时修改了磁盘上的区域,则 CHKDSK 可能会报告磁盘损坏。要正确地进行验证,卷必须处于静止状态,而保证卷处于静止状态的唯一方法就是锁定卷。CHKDSK 仅当您指定了 /F 开关(或 /R 开关,它会隐含指定 /F)时才会锁定卷。在只读模式下,要使 CHKDSK 完成所有运行阶段,可能需要多次运行 CHKDSK。

·         CHKDSK 对 CPU 和磁盘的占用率都很高。运行 CHKDSK 所需的时间要受到系统负载的大小的影响,还要受到 CHKDSK 是联机运行还是在 Windows XP 启动序列内运行的影响。哪个因素成为瓶颈要视硬件配置而定,但是如果在只读模式下运行 CHKDSK 时 CPU 利用率或磁盘 I/O 量很高,则 CHKDSK 的运行时间将变长。此外,Autochk.exe 的运行环境与 Chkdsk.exe 不同。通过 Autochk.exe 运行 CHKDSK 使 CHKDSK 能够独占 CPU 和 I/O 资源,但同时还会使 CHKDSK 无法使用虚拟内存。虽然 Autochk.exe 一般比 Chkdsk.exe 运行速度更快,但如果计算机的可用 RAM 相对较少,Autochk.exe 可能实际上需要更长时间。

·         修复损坏会增加所需的时间。在只读模式下,仅当 CHKDSK 没有发现任何重大损坏时,才能完整运行。如果磁盘仅有少量损坏,那么修复这些问题不会显著增加仅仅运行 CHKDSK 所需的时间。但如果 CHKDSK 发现了重大损坏,例如发生了严重的硬件故障,则运行 CHKDSK 所需的时间将随 CHKDSK 必须修复的损坏文件的数量而成比例地增加。在极端情况下,这可能会成倍地增加 CHKDSK 运行所需的时间。

/C 和 /I 开关简介


/C 开关


/C 开关指示 CHKDSK 跳过在目录结构中检测循环的检查步骤。循环是一种很罕见的损坏形式,此时子目录以其自身为“祖先”。

使用 /C 开关可以将 CHKDSK 的运行速度提高大约 1% 到 2%,但使用此开关也可能会使目录在 NTFS 卷上“循环”。这样的循环可能无法从目录树的其余部分进行访问,而且一些文件可能会被孤立,这意味着 Win32 程序(包括备份程序)将无法看到这些文件。

/I 开关


/I 开关指示 CHKDSK 跳过将目录项与它们的对应文件记录段进行比较的检查步骤。应用此开关时,将仍对目录项进行内部一致性检查,但是目录项未必与相应文件记录段中存储的数据一致。

很难预测通过使用 /I 开关可以节省多少时间。通常,/I 开关可以节省 CHKDSK 50% 到 70% 的运行时间,具体取决于文件与目录个数之比以及磁盘 I/O 速度与 CPU 速度之比等因素。

使用 /I 开关有以下局限:

·         可能会产生引用错误文件记录段的目录项。这种情况下,任何试图使用此类项的程序都会遇到错误。

·         可能会产生没有目录项引用的文件记录段(这是产生孤立文件的另一种方式)。实际上完好无损的文件(如文件记录段所表示的那样)可能对所有的 Win32 程序(包括备份程序)都不可见。

/C 和 /I 开关的价值


在卷上检测到磁盘损坏时,有三个基本的应对选择。

第一个选择是什么都不做。在需要全天 24 小时联机的使命关键服务器上,这通常是必要的选择。缺点是相对较轻的损坏会逐渐发展为重大的损坏。因此,仅当使服务器保持联机比确保损坏卷上所存储数据的完整性更为重要时,才应考虑此选择。在运行 CHKDSK 之前,损坏卷上的所有数据都应当被看作是“危险”的。 第二个选择是运行完整的 CHKDSK 操作,以修复所有文件系统数据并通过自动进程还原所有可以恢复的用户数据。但是,运行完整的 CHKDSK 操作可能会在不适当的时机使得使命关键服务器停机数小时。 第三个选择是通过使用 /C 和 /I 开关中的一个或两个,修复可能会发展为更严重问题的损坏类型(这比完整 CHKDSK 所需的时间少得多),运行简化的 CHKDSK 操作。

但是,请注意,运行简化的 CHKDSK 并不能修复可能存在的所有损坏。您仍需要在将来某个时间运行完整的 CHKDSK,以确保所有可恢复的数据都已实际得到恢复。

另请注意,NTFS 在发生磁盘损坏后并不能保证用户数据的完整性,即使您立即运行了完整的 CHKDSK 操作。CHKDSK 可能无法恢复某些文件,而 CHKDSK 所恢复的某些文件可能内部仍是损坏的。因此,通过执行定期备份或使用某些其他的可靠的数据恢复方法来保护使命关键的数据,仍然是极其重要的。

使用CFile类对文件进行读写

  CFile类提供了对文件进行打开,关闭,读,写,删除,重命名以及获取文件信息等文件操作的基本功能,足以处理任意类型的文件操作

一个读写文件的例子:
文件I/O

  虽然使用CArchive类内建的序列化功能是保存和加载持久性数据的便捷方式,但有时在程序中需要对文件处理过程拥有更多的控制权,对于这种文件输入输出(I/O)服务的需求,Windows提供了一系列相关的API函数,并由MFC将其封装为CFile类,提供了对文件进行打开,关闭,读,写,删除,重命名以及获取文件信息等文件操作的基本功能,足以处理任意类型的文件操作。CFile类是MFC文件类的基类,支持无缓冲的二进制输入输出,也可以通过与CArchive类的配合使用而支持对MFC对象的带缓冲的序列化。

  CFile类包含有一个公有型数据成员m_hFile,该数据成员包含了同CFile类对象相关联的文件句柄。如果没有指定句柄,则该值为CFile::hFileNull。由于该数据成员所包含的意义取决于派生的类,因此一般并不建议使用m_hFile。

  通过CFile类来打开文件可以采取两种方式:一种方式是先构造一个CFile类对象然后再调用成员函数Open()打开文件,另一种方式则直接使用CFile类的构造函数去打开一个文件。下面的语句分别演示了用这两种方法打开磁盘文件“C:\TestFile.txt”的过程:

// 先构造一个实例,然后再打开文件
CFile file;
file.Open(“C:\\TestFile.txt”, CFile::modeReadWrite);
……
// 直接通过构造函数打开文件
CFile file(“C:\\TestFile.txt”, CFile::modeReadWrite);

  其中参数CFile::modeReadWrite是打开文件的模式标志,CFile类中与之类似的标志还有十几个,现集中列表如下:

文件模式标志 说明
CFile::modeCreate  创建方式打开文件,如文件已存在则将其长度设置为0
CFile::modeNoInherit  不允许继承
CFile::modeNoTruncate 创建文件时如文件已存在不对其进行截断
CFile::modeRead 只读方式打开文件
CFile::modeReadWrite 读写方式打开文件
CFile::modeWrite 写入方式打开文件
CFile::shareCompat 在使用过程中允许其他进程同时打开文件
CFile::shareDenyNone 在使用过程中允许其他进程对文件进行读写
CFile::shareDenyRead 在使用过程中不允许其他进程对文件进行读取
CFile::shareDenyWrite 在使用过程中不允许其他进程对文件进行写入
CFile::shareExclusive  取消对其他进程的所有访问
CFile::typeBinary 设置文件为二进制模式
CFile::typeText 设置文件为文本模式

  这些标志可以通过“或”运算符而同时使用多个,并以此来满足多种需求。例如,需要以读写方式打开文件,如果文件不存在就创建一个新的,如果文件已经存在则不将其文件长度截断为0。为满足此条件,可用CFile::modeCreate、CFile::modeReadWrite和CFile::modeNoTruncate等几种文件模式标志来打开文件:

CFile file ("C:\\TestFile.txt", CFile::modeCreate | CFile::modeReadWrite | CFile::modeNoTruncate);

  在打开的文件不再使用时需要将其关闭,即可以用成员函数Close()关闭也可以通过CFile类的析构函数来完成。当采取后一种方式时,如果文件还没有被关闭,析构函数将负责隐式调用Close()函数去关闭文件,这也表明创建在堆上的CFile类对象在超出范围后将自动被关闭。由于调用了对象的析构函数,因此在文件被关闭的同时CFile对象也被销毁,而采取Close()方式关闭文件后,CFile对象仍然存在。所以,在显式调用Close()函数关闭一个文件后可以继续用同一个CFile对象去打开其他的文件。

  文件读写是最常用的文件操作方式,主要由CFile类成员函数Read()、Write()来实现。其函数原型分别为:

UINT Read( void* lpBuf, UINT nCount );
void Write( const void* lpBuf, UINT nCount );

  参数lpBuf为指向存放数据的缓存的指针,nCount为要读入或写入的字节数,Read()返回的为实际读取的字节数,该数值小于或等于nCount,如果小于nCount则说明已经读到文件末尾,可以结束文件读取,如继续读取,将返回0。因此通常可以将实际读取字节数是否小于指定读取的字节数或是否为0作为判断文件读取是否到达结尾的依据。下面这段代码演示了对文件进行一次性写入和循环多次读取的处理过程:

// 创建、写入方式打开文件
CFile file;
file.Open("C:\\TestFile.txt", CFile::modeWrite | CFile::modeCreate);
// 写入文件
memset(WriteBuf, 'a', sizeof(WriteBuf));
file.Write(WriteBuf, sizeof(WriteBuf));
// 关闭文件
file.Close();
// 只读方式打开文件
file.Open("C:\\TestFile.txt", CFile::modeRead);
while (true)
{
// 读取文件数据
int ret = file.Read(ReadBuf, 100);
……
// 如果到达文件结尾则中止循环
if (ret < 100)
break;
}
// 关闭文件
file.Close();

  Write()和Read()函数执行完后将自动移动文件指针,因此不必再显示调用Seek()函数去定位文件指针。包含有文件定位函数的完整代码如下所示:

// 创建、写入方式打开文件
CFile file;
file.Open("C:\\TestFile.txt", CFile::modeWrite | CFile::modeCreate);
// 写入文件
memset(WriteBuf, 'a', sizeof(WriteBuf));
file.SeekToBegin();
file.Write(WriteBuf, sizeof(WriteBuf));
// 关闭文件
file.Close();
// 只读方式打开文件
file.Open("C:\\TestFile.txt", CFile::modeRead);
while (true)
{
// 文件指针
static int position = 0;
// 移动文件指针
file.Seek(position, CFile::begin);
// 读取文件数据
int ret = file.Read(ReadBuf, 100);
position += ret;
……
// 如果到达文件结尾则中止循环
if (ret < 100)
break;
}
// 关闭文件
file.Close();

 

补充:

使用CFile类对文件进行按结构读取,如:

CFile fileRead,fileWrite;
 fileRead.Open(_T("E:\\a.dat"),CFile::modeRead);//这里使用宏_T
 fileWrite.Open(_T("E:\\backup.txt"),CFile::modeCreate | CFile::modeWrite);

VIDEOHEADER *videoheader=new VIDEOHEADER();
fileRead.Read(videoheader,sizeof(VIDEOHEADER));
char buf[sizeof(VIDEOHEADER)*8];
sprintf(buf,"videoheader.cCommandID:%s ,videoheader->cCommandID);通过sprintf对我们需要写入文件中的数据进行格式化,这样在文件中存储的数据就是以这里定义的格式显示的。
fileWrite.Write(buf,strlen(buf));  

VC 用函数读写INI配置文件

ini文件(即Initialization file),这种类型的文件中通常存放的是一个程序的初始化信息。ini文件由若干个节(Section)组成,每个Section由若干键(Key)组成,每个Key可以赋相应的值。读写ini文件实际上就是读写某个的Section中相应的Key的值,而这只要借助几个函数即可完成。
一、向ini文件中写入信息的函数
1. 把信息写入系统的win.ini文件
BOOL WriteProfileString(
     LPCTSTR lpAppName, // 节的名字,是一个以0结束的字符串
     LPCTSTR lpKeyName, // 键的名字,是一个以0结束的字符串。若为NULL,则删除整个节
     LPCTSTR lpString      // 键的值,是一个以0结束的字符串。若为NULL,则删除对应的键
)

2. 把信息写入自己定义的.ini文件
BOOL WritePrivateProfileString(
     LPCTSTR lpAppName,     // 同上
     LPCTSTR lpKeyName,     // 同上
     LPCTSTR lpString,      // 同上
     LPCTSTR lpFileName     // 要写入的文件的文件名。若该ini文件与程序在同一个目录下,也可使用相对
           //路径,否则需要给出绝度路径。
)
如:
::WriteProfileString("Test","id","xym"); 
//在win.ini中创建一个Test节,并在该节中创建一个键id,其值为xym
::WritePrivateProfileString("Test","id","xym","d:\\vc\\Ex1\\ex1.ini");
//在Ex1目录下的ex1.ini中创建一个Test节,并在该节中创建一个键id,其值为xym
//若Ex1.ini文件与读写该文件的程序在同一个目录下,则上面语句也可写为:
::WritePrivateProfileString("Test","id","xym",".\\ex1.ini");
需要注意的是,C系列的语言中,转义字符'\\'表示反斜线'\'。另外,当使用相对路径时,\\前的.号不能丢掉了。
二、从ini文件中读取数据的函数
1、从系统的win.ini文件中读取信息
(1) 读取字符串
DWORD GetProfileString(
     LPCTSTR lpAppName,           // 节名
     LPCTSTR lpKeyName,           // 键名,读取该键的值
     LPCTSTR lpDefault,           // 若指定的键不存在,该值作为读取的默认值
     LPTSTR lpReturnedString,     // 一个指向缓冲区的指针,接收读取的字符串
     DWORD nSize                  // 指定lpReturnedString指向的缓冲区的大小
)
如:
CString str;
::GetProfileString("Test","id","Error",str.GetBuffer(20),20);
(2) 读取整数
UINT GetProfileInt(
     LPCTSTR lpAppName,     // 同上
     LPCTSTR lpKeyName,     // 同上
     INT nDefault           // 若指定的键名不存在,该值作为读取的默认值
)
如使用以下语句写入了年龄信息:
::WriteProfileString("Test","age","25"); 
//在win.ini中创建一个Test节,并在该节中创建一个键age,其值为25
则可用以下语句读取age键的值:
int age;
age=::GetProfileInt("Test","age",0);
2、从自己的ini文件中读取信息
(1) 读取字符串
DWORD GetPrivateProfileString(
     LPCTSTR lpAppName,           // 同1(1)
     LPCTSTR lpKeyName,           // 同1(1)
     LPCTSTR lpDefault,           // 同1(1)
     LPTSTR lpReturnedString,     // 同1(1)
     DWORD nSize,                 // 同1(1)
     LPCTSTR lpFileName           // 读取信息的文件名。若该ini文件与程序在同一个目录下,也可使用相     
           //对路径,否则需要给出绝度路径。
)
如:
CString str;
::GetPrivateProfileString("Test","id","Error",str.GetBuffer(20),20,".\\ex1.ini");
或:
::GetPrivateProfileString("Test","id","Error",str.GetBuffer(20),20,"d:\\vc\\Ex1\\ex1.ini");
(2) 读取整数
UINT GetPrivateProfileInt(
     LPCTSTR lpAppName,     // 同上
     LPCTSTR lpKeyName,     // 同上
     INT nDefault,          // 若指定的键名不存在,该值作为读取的默认值
     LPCTSTR lpFileName     // 同上
)
如使用以下语句写入了年龄信息:
::WritePrivateProfileString("Test","age","25",".\\ex1.ini"); 
//在ex1.ini中创建一个Test节,并在该节中创建一个键age,其值为25
则可用以下语句读取age键的值:
int age;
age=::GetPrivateProfileInt("Test","age",0,".\\ex1.ini");
三、 删除键值或节
      回顾一下WriteProfileString函数的说明
BOOL WriteProfileString(
     LPCTSTR lpAppName, // 节的名字,是一个以0结束的字符串
     LPCTSTR lpKeyName, // 键的名字,是一个以0结束的字符串。若为NULL,则删除整个节
     LPCTSTR lpString      // 键的值,是一个以0结束的字符串。若为NULL,则删除对应的键
)
      由此可见,要删除某个节,只需要将WriteProfileString第二个参数设为NULL即可。而要删除某个键,则只需要将该函数的第三个参数设为NULL即可。这是删除系统的win.ini中的节或键,类似的,要删除自己定义的ini文件中的节或键,也可做相同的操作。
      如:
::WriteProfileString("Test",NULL,NULL);     //删除win.ini中的Test节
::WriteProfileString("Test","id",NULL);     //删除win.ini中的id键

::WritePrivateProfileString("Test",NULL,NULL,".\\ex1.ini");     //删除ex1.ini中的Test节
::WritePrivateProfileString("Test","id",NULL,".\\ex1.ini");     //删除ex1.ini中的id键
四、如何判断一个ini文件中有多少个节
      要判断一个ini文件中有多少个节,最简单的办法就是将所有的节名都找出来,然后统计节名的个数。而要将所有的节名找出来,使用GetPrivateProfileSectionNames函数就可以了,其原型如下:
DWORD GetPrivateProfileSectionNames(
     LPTSTR lpszReturnBuffer,     // 指向一个缓冲区,用来保存返回的所有节名
     DWORD nSize,                 // 参数lpszReturnBuffer的大小
     LPCTSTR lpFileName           // 文件名,若该ini文件与程序在同一个目录下,
                                               //也可使用相对路径,否则需要给出绝度路径
)

tar 文件格式