书籍:《Visual C++ 2017从入门到精通》的2.10 文件操作
环境:visual studio 2022
内容:[例 2.53] 读写一个临时文件
1. 功能概述
GetTempFileName()
是 Windows API 中用于生成唯一临时文件名的核心函数。其生成的文件名通常用于:
- 临时存储应用程序运行时的中间数据。
- 避免文件名冲突(如多线程/多实例程序)。
- 需要程序结束后手动删除的临时资源。
2. 函数原型与参数
C/C++ 原型
UINT GetTempFileName(
LPCTSTR lpPathName, // 临时文件目录路径
LPCTSTR lpPrefixString,// 文件名前缀
UINT uUnique, // 唯一性标识(0 表示自动生成)
LPTSTR lpTempFileName // 接收生成的文件名缓冲区
);
参数详解
参数名 | 类型 | 描述 |
---|---|---|
lpPathName | LPCTSTR | 临时文件目录路径(需包含终止符 \ )。常用 GetTempPath() 获取。 |
lpPrefixString | LPCTSTR | 文件名前缀(最多 3 个字符会被使用)。例如前缀为 TMP ,则文件名形如 TMP1234.tmp 。 |
uUnique | UINT | 唯一性标识: - 0 :自动生成唯一编号(基于时间戳 + 随机数)。- 非零:直接追加该数字到前缀后(不检查唯一性)。 |
lpTempFileName | LPTSTR | 接收结果的缓冲区(需 ≥ MAX_PATH 字符)。 |
返回值
- 成功:返回生成文件名中的唯一数字部分(如
1234
)。 - 失败:返回
0
,需通过GetLastError()
获取错误码。
3. 文件名生成规则
-
格式:
<路径>\<前缀><唯一标识>.tmp
- 路径:由
lpPathName
指定(如C:\Temp\
)。 - 前缀:取
lpPrefixString
的前 3 个字符(如TMP
)。 - 唯一标识:
- 若
uUnique=0
:生成 4 位十六进制数(如A1B2
)。 - 若
uUnique≠0
:直接追加该数字(如1234
)。
- 若
- 路径:由
-
示例:
lpPathName = "C:\Temp\"
,lpPrefixString = "DATA"
,uUnique=0
→C:\Temp\DATA1A2B.tmp
lpPathName = "C:\Temp\"
,lpPrefixString = "LOG"
,uUnique=9999
→C:\Temp\LOG9999.tmp
4. 使用场景
- 临时数据存储:如缓存计算结果、会话数据。
- 多进程协作:避免不同进程生成同名文件。
- 自动化测试:创建临时测试文件并自动清理。
5. 代码示例
C++ 示例
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
int main() {
TCHAR szTempPath[MAX_PATH] = {0};
TCHAR szTempFile[MAX_PATH] = {0};
// 获取临时目录路径
if (GetTempPath(MAX_PATH, szTempPath) == 0) {
_tprintf(_T("获取临时路径失败,错误码:%lu\n"), GetLastError());
return 1;
}
// 生成临时文件名
UINT uResult = GetTempFileName(szTempPath, _T("TMP"), 0, szTempFile);
if (uResult == 0) {
_tprintf(_T("生成临时文件名失败,错误码:%lu\n"), GetLastError());
return 1;
}
_tprintf(_T("临时文件路径:%s\n"), szTempFile);
// 创建并写入文件(可选)
HANDLE hFile = CreateFile(szTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
const char* szData = "Hello, Temp File!";
DWORD dwWritten = 0;
WriteFile(hFile, szData, strlen(szData), &dwWritten, NULL);
CloseHandle(hFile);
}
return 0;
}
VB 示例
Private Declare Function GetTempFileName Lib "kernel32" Alias "GetTempFileNameA" _
(ByVal lpszPath As String, ByVal lpPrefixString As String, _
ByVal wUnique As Long, ByVal lpTempFileName As String) As Long
Sub Main()
Dim tempPath As String
Dim tempFile As String
Dim result As Long
' 获取临时路径
tempPath = GetTempPath() ' 需自行实现或调用 API
' 生成临时文件名
result = GetTempFileName(tempPath, "TEST", 0, tempFile)
If result = 0 Then
MsgBox "生成临时文件名失败,错误码:" & Err.LastDllError
Else
MsgBox "临时文件路径:" & tempFile
End If
End Sub
C# 示例
using System;
using System.IO;
using System.Runtime.InteropServices;
class Program {
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern uint GetTempFileName(
string lpPathName,
string lpPrefixString,
uint uUnique,
StringBuilder lpTempFileName);
static void Main() {
string tempPath = Path.GetTempPath();
StringBuilder tempFile = new StringBuilder(260);
uint result = GetTempFileName(tempPath, "DATA", 0, tempFile);
if (result == 0) {
Console.WriteLine("生成临时文件名失败,错误码:" + Marshal.GetLastWin32Error());
} else {
Console.WriteLine("临时文件路径:" + tempFile.ToString());
}
}
}
6. 关键注意事项
-
路径有效性:
- 确保
lpPathName
是有效目录(可通过GetTempPath()
获取)。 - 路径长度需 ≤
MAX_PATH - 14
(避免缓冲区溢出)。
- 确保
-
唯一性控制:
- 当
uUnique=0
时,若短时间内生成大量文件(如超过 65535 个),可能失败。 - 非零
uUnique
需自行确保唯一性。
- 当
-
文件清理:
- 生成的临时文件不会被系统自动删除,需手动调用
DeleteFile
或File.Delete
。
- 生成的临时文件不会被系统自动删除,需手动调用
-
跨平台限制:
- 仅限 Windows 系统,Linux/macOS 需使用其他方法(如
mkstemp
或tempfile
模块)。
- 仅限 Windows 系统,Linux/macOS 需使用其他方法(如
7. 错误处理
错误码 | 含义 | 解决方案 |
---|---|---|
ERROR_BUFFER_OVERFLOW | 路径超过 MAX_PATH - 14 字符 | 缩短路径或使用绝对路径 |
ERROR_INVALID_PARAMETER | 参数无效(如空路径) | 检查参数合法性 |
ERROR_SEM_FAILCRITICALOPS | 资源不足 | 释放资源后重试 |
8. 扩展应用
- 批量生成临时文件:
通过循环调用GetTempFileName()
生成多个文件,适用于测试场景。 - 自定义临时目录:
结合GetTempPath()
和SetCurrentDirectory()
动态切换目录。
9. 跨语言对比
语言 | 函数/方法 | 特点 |
---|---|---|
C/C++ | GetTempFileName() | 原生 API,灵活控制路径和前缀。 |
VB | GetTempFileName API 声明 | 需手动声明外部函数,兼容旧版 VB。 |
C# | P/Invoke 调用或 Path.GetTempFileName() | 后者更简单(返回完整路径),但无法自定义前缀。 |
Python | tempfile.mktemp() | 自动生成唯一文件名,但需注意安全性(避免路径注入)。 |
通过合理使用 GetTempFileName()
,开发者可以高效管理临时资源,同时避免文件名冲突问题。