Windows的MAX_PATH

MAX_PATH的解释: 文件名最长256(ANSI),加上盘符(X:\)3字节,259字节,再加上结束符1字节,共260
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
http://support.microsoft.com/kb/320081

windows下,全文件名的字符长度是有限制的,众所周知,是MAX_PATH,260。对于这个,几点具体解释:
1. 这个260指的是包含目录到文件名的全路径字符长度。
2. 实际上,测试可以发现:
--加上null,你在资源管理器里只能创建259个字符的全文件名,即实际上只能创建MAX_PATH -2 = 258字符的路径。
--你可以创建c:\长目录\abc.txt <= 258,也可以创建c:\abc\长文件名.txt <= 258。
--创建每一级目录的时候,可以输入的目录名字符是有限制的,规则就是:至少保留下了 11个字符(8.3规则?)使得最内层目录仍然可以创建出文件。
--但是,比如你创建了C:\abc\长文件名.txt,然后呢,重命名目录abc,这时候,你可以创建出一个总长度超过MAX_PATH的全文件名。相当tricky。

参考: http://blog.163.com/[email protected]/blog/static/3606944620105109561679/

------------------------------ 解决方案一 ------------------------------
http://www.debugease.com/csharp/1202792.html
那你不要用它的全路径来创建,用某个文件夹的DirectoryInfo来创建不就好了
多谢提醒,取得父文件夹路径CreateSubdirectory就可以了。试了好多方法,怎么把这个忘了,汗一下自己。

让我们从BCL中的一个有趣的异常开始今天的话题:[PathTooLongException]: The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.我们的客户在bug报告里说: “路径最多只有260个字符? MS搞笑的吧. 把这个限制搞得更长一些!”. 在这里我将会对这些提交bug报告的人(很抱歉你们的bug被关成了”won’t fix”)详细解释这个问题并告诉你们我们对此所作出的努力.让我们先来澄清一些术语:Path: 一个文件的全路径. 比如你又一个文件: c:\temp\fileA.txt, 那么通常你会叫这个文件fileA.txt, 但它的全路径应该是c:\temp\fileA.txt.
MAX_PATH: Windows API定义的路径的最大长度, 260个字符.
Long path: 一个长度超过了MAX_PATH的路径.
Long file name: 跟long path还不一样. 这个其实是用来跟短文件名作对比的, 就是以前我们说的那个8.3格式的文件名.
众所周知.NET API是依赖于Windows API的, 从这一点上看, 上面的这个异常就没有什么问题了. 然而Windows API还提供了一个方法来绕过这个MAX_PATH的限制. 如果你在你的文件路径前面加上”\\?\”的前缀, 然后调用unicode版本的Windows API, 那么你的path的最大长度就可以达到32k了. 也就是说你只要加上前缀”\\?\”就可以在Windows API中使用long path了.没有人会抱怨32k的长度限制了, 那么是不是就可以说问题解决了呢? 也不完全是. 过去我们不愿意支持long path是有原因的, 而且现在我们还会考虑这些原因. 第一个原因就是安全. 前缀”\\?\”并不仅仅是打破的long path的限制, 它还能让path在到达文件系统之前只受到Windows API的最小的修正. 这样做的结果就是”\\?\”规避了Windows API对于path的一系列的标准化的操作: 去掉path后面的空格, 把’.’和’..’扩展为相应的内容, 以及把相对路径转换成全路径等等. 在.Net中的如果用FileIOPermission attribute来保证安全, 我们就不得不使用标准化后的路径. 而不用FileIOPermission就会有安全隐患. 现在我们明白了如果我们用前缀”\\?\”来解决long path的问题的话, 我们就必须能像Windows API那样把路径标准化.第二个原因是支持long path可能导致的不一致行为. 很多操作文件的Windows API都支持以”\\?\” 作为前缀的long path, 但仅仅是很多而不是全部. 比如LoadLibrary, 它的功能是将一个module映射到调用者的地址空间, 在文件路径超过MAX_PATH的时候就会失败. 这就意味着你可以调用MoveFile把一个DLL放到一个路径长度超过MAX_PATH的地方, 但是当你想加载这个DLL的时候却失败了. 在Windows API里面有很多这样的例子, 虽然有一些权宜之计, 但都是针对特殊问题的, 没有一个通用的解决方案.另外一个因素, 也是最痛苦的一个, 是Windows Application和Windows shell本身在long path上的兼容性. 因为Windows shell本身只支持长度小于260的路径 (下面会讲到Vista shell弱化了这个限制). 就是说如果.NET支持了long path, 那么你就可以通过你的.NET App创建一些在Explorer或是命令行中不能访问的文件了. J我们已经意识到了260个字符的限制并不是很合理. 我们的客户并不经常碰到这个问题, 但是一旦需要一个超出MAX_PATH的路径, 就会觉得很不方便. 一个权宜之计是P/Invoking Windows API并使用”\\?\”前缀, 但是这样就不得不写一大坨跟System.IO重复的code. 所以为了解决这个问题, 我们的客户常常会重新设计目录结构, 绞尽脑汁的缩短目录名. 因为这个问题已经逐渐变得普遍, 所以无论是.NET framework还是别的领域, MS都已经开始着手解决这个问题. 实际上在vista中你应该已经可以看到我们为了减少出现MAX_PATH的问题的几率所作出的改动: 很多特定的目录名已经被缩短 (译注: \Documents and Settings à \Users, 实际上, 在MS有一个专门的alias叫longpath来谈论这个问题), shell还有一个auto-path shrinking的功能, 它会用比较短的别名来表示路径以把那些long path压缩在260个字符以内.

------------------------------ 解决方案二 ------------------------------
http://express.ruanko.com/ruanko-express_11/webpage/tech-overnight_1.html

上层逻辑控制和事务处理使用 Java 开发,而底层核心功能使用 C/C++ 实现,这已经成为一种较为通用的开发模式。但由于 Windows 操作系统的默认设置,上述语言在对长路径名(>260 字符)文件的处理时会遇到一些问题。本文列出了不同的 JDK 版本在 Windows 操作系统上对于长路径名文件处理的区别,给出了两种支持长路径名文件的 C/C++ 编程方法,同时还指出了从 JDK 5.0 开始才完全支持长路径名。使用本文的方法,可以解决在 Windows 平台上标准 API 函数对长路径名文件支持的局限性问题,给开发测试工作带来方便。

Windows 对长路径名文件的限制

众所周知,微软的文件系统经历了 fat->fat32->NTFS 的技术变革。且不论安全和文件组织方式上的革新,单就文件名而言,已经从古老的 DOS 8.3 文件格式(仅支持最长 8 个字符的文件名和 3 个字符的后缀名)转变为可以支持长达 255 个字符的文件名。而对于路径长度,NTFS 也已经支持长达 32768 个字符的路径名。

然而,Windows 操作系统并没有完全放开路径名长度的限制,在 windef.h 中,可以找到如下的宏:

#define MAX_PATH 260

事实上,所有的 Windows API 都遵循这个限制。因此,每当我们试图更改某一文件的文件名时,当输入的文件名长度 ( 全路径 ) 到达一定限度时,虽然文件名本身还未达到 255 个字符的限制,但是任何输入将不再被接受,这其实正是由于操作系统不允许 260 个字符(byte)的文件全路径。

实际应用中,这种 260 个字符的全路径的限制给应用开发带来了很大的不便。试想如下应用:我们希望给应用服务器增加一个本地 cache 的功能,该功能可以把远程服务器上的文件留下一个本地的副本。一个合理的实现可以把 url 映射为文件名,当 url 很长时,cache 文件的长度也会很长。当文件名长度超过 255,我们可以把映射文件名的前 255 个字符作为目录名称。但是,我们仍然无法解决 260 个字符的全路径限制。另外,如果一个应用软件的目录结构过深,很容易出现某些文件名长度(含路径)超过 260 个字符,并因此造成安装或删除的失败。总而言之,该限制给我们的开发测试工作带来了诸多不便。

对于一些网络服务器,往往需要将 Java 代码用于上层逻辑控制 / 事务处理的开发,同时将 C/C++ 用于底层核心功能的实现。为此,我们研究了这两种程序语言对长路径名文件的支持情况。其中,对于 Java,比较了两个常用版本 1.4 和 5.0 对长路径支持的差异性;对于 C/C++ 语言的局限性,提出了我们的解决方法。

实验环境
操作系统: Windows xp
文件系统: NTFS 文件系统
Java 编译环境:JDK 1.4.2 以及 JDK 5.0
C++ 编译环境: VC.net

在 Java 中使用长路径名文件

Java 语言并不需要对长路径名文件进行特殊的处理,就可以支持长路径名文件的创建、读写和删除操作等基本操作。但是,JDK 1.4.2 和 JDK 5.0 在长路径的支持上是不同的,JDK 1.4.2 并不是完全支持所有的长路径名文件操作,比如访问文件属性的操作是不支持的。我们设计了如下代码来验证 JDK 1.4.2 和 JDK 5.0 对长路径名文件支持的区别。

清单 1. 对长路径名文件操作的 Java 实验代码:

try {
    String fileName = "E:\\VerylongpathVerylongpathVerylongpath
        VerylongpathVerylongpathVerylongpathVerylongpath
        VerylongpathVerylongpathVerylongpathVerylongpath\	VerylongpathVerylongpathVerylongpathVery
        longpathVerylongpathVerylongpathVerylongpath
	VerylongpathVerylongpathVerylongpathVerylongpa
        th.txt";
    System.out.println("Filename: " + fileName);
    System.out.println("File path length: " + fileName.length());
    String renameFileName = "E:\\VerylongpathVerylongpathVerylongpath
        VerylongpathVerylongpathVerylongpathVerylongpath
        VerylongpathVerylongpathVerylongpathVerylongpath\\Short.txt";

    //Create the file.
    File file = new File(fileName);
    if (!file.exists())
        file.createNewFile();
    if (file.exists())
        System.out.println("The file exists!");
    if (file.canRead())
        System.out.println("The file can be read!");
    if (file.canWrite())
        System.out.println("The file can be written!");
    if (file.isFile())
        System.out.println("It‘s a file!");

    //Write to the created file.
    FileOutputStream out = new FileOutputStream(file);
    PrintStream p = new PrintStream(out);
    p.println("This is only a test!");
    p.close();

    //Read the information from that file.
    BufferedReader br = new BufferedReader(new FileReader(file));
    StringBuffer sb = new StringBuffer();
    while (true) {
        String sl = br.readLine();
        if (sl == null) {
            break;
        } else {
            sb.append(sl + "\n");
        }
    }
    br.close();
    System.out.println("The content in the file:");
    System.out.print("\t" + sb.toString());

    //File rename
    File newfile = new File(renameFileName);
    if (newfile.exists())
        System.out.println(renameFileName + "exsited");
    else {
        if (file.renameTo(newfile)){
            System.out.println("Rename sucessful!");
        } else {
            System.out.println("Rename failed!");
        }
    }

    //delete file
    if (file.delete())
        System.out.println("The old file deleted!");
    if (newfile.delete())
        System.out.println("The renamed file deleted!");
    }  catch (IOException e) {
        //Error happened
        e.printStackTrace();
        System.out.println("Error occurs in writing to the file.");
    }
}

清单 2. 使用jdk1.42 的结果

Filename: E:\VerylongpathVerylongpathVerylongpath
VerylongpathVerylongpathVerylongpathVerylongpathVer
ylongpathVerylongpathVerylongpathVerylongpathVerylongpathVerylongpathVerylongpathVerylong
pathVerylongpathVerylongpathVerylongpath
VerylongpathVerylongpathVerylongpathVerylongpath.t
xt

File path length: 272

The content in the file:

This is only a test!

Rename failed!

The old file deleted!

从实验结果来看,JDK 1.4.2 得到了该长路径名文件的内容,因此,对于该长路径名文件的创建以及读写操作都是支持的。但是对比下文使用 JDK 5.0 的结果,可以看到,所有对于文件属性的判断都是错误的,同时,重命名的操作也无法实现。更为重要的是,JDK 1.4.2 存在着一个很致命的问题,即方法 File.exists() 是失效的。通常,在删除文件前,需要调用该方法判断文件是否存在,对于 JDK 1.4.2,如果直接去删除一个不知道是否存在的文件,就会存在比较大的风险。因此,JDK 1.4.2 在 Windows 平台对长路径名文件的操作只是有限的支持,使用的时候,一定要注意。

清单 3. 使用jdk5.0 的结果

Filename: E:\VerylongpathVerylongpathVerylongpath
VerylongpathVerylongpathVerylongpathVerylongpathVer
ylongpathVerylongpathVerylongpathVerylongpathVerylongpathVerylongpathVerylongpathVerylong
pathVerylongpathVerylongpathVerylongpath
VerylongpathVerylongpathVerylongpathVerylongpath.t
xt
File path length: 272
The file exists!
The file can be read!
The file can be written!
It‘s a file!
The content in the file:
	This is only a test!
Rename sucessful!
The renamed file deleted!

从实验中可以清楚的看到,在版本 JDK 5.0 中,所有的文件操作(新建、读写、属性操作、重命名、删除等)都能够得到正确的处理。使用 JDK 5.0 就可以完全不用担心长路径名文件的使用问题。

在 C/C++ 中使用长路径名文件

相对于 JDK 5.0 不需要任何改动就可以支持长路径名文件,在 C/C++ 中使用超过 260 个字符的路径长度的文件,会复杂得多。下面介绍两种支持长路径名文件的方法。

方法一:使用 Unicode 版本的 API

从微软官方网站 Path Field Limits,可以查到,使用 Unicode 版本的 API,对于使用 NTFS 文件系统的 Windows NT 4.0, Windows 2000, Windows XP Home Edition, Windows XP Professional 和 Windows Server 2003 操作系统,可以支持 32768 字节的文件路径长度。同时,路径名必须使用 \\?\ 的前缀。依照这个思路,我们设计了实验。

清单 4. 对长路径名文件操作的 C 的示例代码(Unicode API)

{
FILE *from, *to;
char filename[1024];
strcpy(filename,"\\\\?\\E:\\VerylongpathVerylongpathVerylongpathVerylongpathVerylongpathV
erylongpathVerylongpathVerylongpathVerylongpathVerylongpathVerylongpath\\VerylongpathVeryl
ongpathVerylongpathVerylongpathVerylongpathVerylongpathVerylongpathVerylongpathVerylongpat
hVerylongpathVerylongpath.txt");
int iL1=MultiByteToWideChar(CP_ACP, 0, filename, strlen(filename), NULL, 0);
WCHAR* wfilename=new WCHAR[iL1+1];
wfilename[iL1] = ‘\0‘;
int iL2=MultiByteToWideChar(CP_ACP, 0, filename, strlen(filename), wfilename, iL1);
from = _wfopen( wfilename ,L"rb");
to = fopen(".\\longpath.txt", "wb");
if((from ==NULL)||(to==NULL))
    return -1;
char buffer[1024];
int count = 0;
while ( (count = fread(buffer, sizeof(char), 1024, from)) != 0)
    fwrite( buffer, sizeof(char), count, to);
delete []wfilename;
fclose (from); fclose(to);
}

使用如上的方法,我们可以拷贝某长路径名的文件到当前文件夹中。从试验结果看,该方法是有效的。但是,由于该方法要求系统使用 Unicode 的 API,同时需要更改路径名称以及编码方式。因此,对于一个已经存在的系统,由于需要改变所有文件操作相关的 API,因此改动将会很大。

方法二:创建 8.3 格式的短路径名

对于每一个长路径名,都有一个 8.3 格式(8 个字符的文件名和 3 个字符的后缀名)的短路径名与其相对应,任意的文件夹或者文件名都可以映射成一个 8 字符的文件名(A~B),其中 A 是文件名前缀,B 是表示字母序的顺序。操作系统可以保证这样的映射是一对一的,只要使用 GetShortPathName() 将长路径名转成相应的短路径名,就可以进行对该文件进行普通的文件操作。同时,在任何时候都可以用函数 GetLongPathName() 把 8.3 格式的短路径名恢复成初始的长路径名。

如 GetShortPathName Function叙述,我们需要一个 Unicode 版本的 API,同时在路径名前加上 \\?\ 的前缀,才能实现长短路径名间的切换。但从实验来看,即使不使用 Unicode 的 API,依然可以实现上述功能。

清单 5. 对长路径名文件操作的 c 的示例代码(ShortPath)

{
char pathName [1024];
strcpy(pathName,"\\\\?\\E:\\VerylongpathVerylongpathVerylongpathVerylongpathVerylongpathV
erylongpathVerylongpathVerylongpathVerylongpathVerylongpathVerylongpath\\VerylongpathVeryl
ongpathVerylongpathVerylongpathVerylongpathVerylongpathVerylongpathVerylongpathVerylongpat
hVerylongpathVerylongpath.txt");

const int MaxPathLength = 2048;
char shortPath[MaxPathLength];

if (strlen(pathName) >= MAX_PATH)
{
    char prePath[] = "\\\\?\\";
    if (strlen(pathName) >= MaxPathLength - strlen(pathName))
        return false;

    sprintf(shortPath, "%s%s", prePath, pathName);

    for (int iPathIndex = 0; iPathIndex < strlen(shortPath); iPathIndex++)
        if (shortPath[iPathIndex] == ‘/‘)
            shortPath[iPathIndex] = ‘\\‘;

    int dwlen = GetShortPathName(shortPath, shortPath, MaxPathLength);
    if (dwlen <= 0)
        return false;
}
}

经过上述的代码,超过 MAX_PATH 限制的路径名都可以转变成一个 8.3 格式的短路径名,可以把这个文件名 (shortPath)作为后续文件操作函数的参数。这种情况下,对于该文件的所有操作都可以被支持了。我们用这种缩短路径名长度的方式解决了长路径名文件的操作问题。

结束语

本文首先列出了不同的 JDK 版本在 Windows 操作系统上对于长路径名文件处理的区别,同时指出了 JDK 5.0 开始才完全支持长路径名;在第二部分中给出了两种支持长路径名文件的 C/C++ 编程方法。使用上文中的任一方法,我们都可以实现对长路径名文件的操作,这将在很大程度上方便我们的开发工作,解决在 Windows 平台上标准 API 函数对长路径名文件支持的局限性问题。

Windows的MAX_PATH

时间: 2024-10-10 06:06:40

Windows的MAX_PATH的相关文章

小练习:用socket实现Linux和Windows之间的通信

在日常生活中,绝大部分人使用的机器一般是windows系统,但是对于研发人员,开发.编译等工作往往是建立在linux机器上.事实上,在服务器方面,Linux.UNIX和WindowsServer占据了市场的大部分份额:在超级计算机方面,Linux取代Unix成为了第一大操作系统. 通信是计算机和操作系统的一大任务,通过ftp.ping.ssh等方式,人们可以很方便与服务器连接.一个庞大的网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket.windows系统使

(8)Linux(客户端)和Windows(服务端)下socket通信实例

Linux(客户端)和Windows(服务端)下socket通信实例: (1)首先是Windows做客户端,Linux做服务端的程序 Windows   Client端 #include <stdio.h> #include <Windows.h> #pragma comment(lib, "ws2_32.lib") #define Port 5000 #define IP_ADDRESS "192.168.1.30"     //服务器地址

Windows API参考大全新编

书名:新编Windows API参考大全 作者:本书编写组 页数:981页 开数:16开 字数:2392千字 出版日期:2000年4月第二次印刷 出版社:电子工业出版社 书号:ISBN 7-5053-5777-8 定价:98.00元 内容简介 作为Microsoft 32位平台的应用程序编程接口,Win32 API是从事Windows应用程序开发所必备的.本书首先对Win32 API函数做完整的概述:然后收录五大类函数:窗口管理.图形设备接口.系统服务.国际特性以及网络服务:在附录部分,讲解如何

vc++基础班[24]---系统各种路径信息的获取

------------------------------------------ Begin ---------------------------------------- ①.Windows.System32.temp 等目录的获取: TCHAR szPath[MAX_PATH] = {0}; GetSystemDirectory(szPath, MAX_PATH); //C:\WINDOWS\system32 GetWindowsDirectory(szPath, MAX_PATH);

VC 宏与预处理使用方法总结

目录(?) C/C++ 预定义宏^ C/C++ 预定义宏用途:诊断与调试输出^ CRT 和 C 标准库中的宏^ NULL 空指针^ limits.h 整数类型常量^ float.h 浮点类型常量^ math.h 数学常量^ EOF 常量^ errno.h 错误代码^ locale 类别^ _MAX_PATH 等文件名与路径长度限制^ RAND_MAX 随机数最大值^ va_arg/va_start/va_end 访问变长函数参数^ 宏实现的 CRT 函数^ Microsoft 预定义宏^ 平台与

C/C++ 中宏与预处理使用方法大全 (VC)

VC 中的宏使用方法参考 MSDN: Macros (C/C++) C/C++ 预定义宏^ __LINE__: 当前源文件的行号,整数__FILE__: 当前源文件名,char 字符串,使用 /FC 选项产生全路径__DATE__: 当前编译日期,char 字符串,格式 Aug 28 2011__TIME__: 当前编译时间,char 字符串,格式 06:43:59__STDC__: 整数 1,表示兼容 ANSI/ISO C 标准,配合 #if 使用__TIMESTAMP__: 最后一次修改当前

Windows - 你可以在Windows中做出一个全路径文件名(Fully Qualified File Name)长度超出MAX_PATH=260字节的文件

在任意一个目录下新建一个文件夹. 在该新建文件夹下创建任意一个文件:重命名该文件,使文件名长度不能再长为止. 重命名该新建文件夹,使该文件夹的名字长度更长. 综上,你就在Windows中做出了一个全路径文件名长度超出MAX_PATH=260字节的文件. Windows - 你可以在Windows中做出一个全路径文件名(Fully Qualified File Name)长度超出MAX_PATH=260字节的文件

【Windows编程】系列第八篇:通用对话框

上一篇我们学习了菜单的基本编程,本篇来了解一下通用对话框的使用.Windows系统之所以是目前最流行的桌面系统,也是因为Windows有一套标准化,统一友好的交互界面,比如菜单.工具栏.状态栏以及各个控件.当然除了这些单独的控件之外,对于像文件打开.保存对话框,字体对话,颜色对话框等对于Windows本身会用到,在很多第三方的应用程序中也会用到.因此微软公司也早就清楚这种现实情况会存在,所以Windows把这种常见的公共对话就做了统一的接口函数,供Windows自己和第三方开发者使用. Wind

无法删除 NTFS 盘上的文件或文件夹(对Windows文件的各种情况有比较详细的描述)

简介 本文介绍您可能无法删除 NTFS 文件系统卷上的文件或文件夹的原因,以及如何分析造成此问题的不同原因从而解决此问题. 更多信息 注意:在内部,NTFS 将文件夹作为特殊类型的文件进行处理.因此,本文中的“文件”一词可能指文件,也可能指文件夹. 原因 1:文件使用了 ACL 如果某个文件使用了访问控制列表 (ACL),您可能无法删除该文件.要解决此问题,请更改该文件上的权限.您可能需要拥有这些文件的所有权才能更改权限. 管理员具有取得任何文件所有权的隐含能力,即使未明确向他们授予针对此文件的