EGE专栏:EGE专栏
1. 文件路径
文件路径 是用于描述文件系统资源的一个文本标识。文件系统是对文件存储设备的空间进行组织和分配,负责文件存储并对存入的文件进行保护和检索的系统。文件存放在外部存储器中的某些位置上,经由文件系统管理后,被系统以文件路径标识,系统可以通过文件路径检索到对应文件。
1.1 DOS路径的构成
标准的 DOS 路径可由以下三部分组成:
- 卷号或驱动器号,后跟卷分隔符
:
- 目录名。 目录分隔符 (
/
或\
) 用来分隔嵌套目录层次结构中的子目录。 - 可选的文件名。 目录分隔符(
/
或\
) 用来分隔文件路径和文件名。
① 如果一个路径中没有文件名部分,那么此路径对应的是一个目录,如:C:/Users/Names/
。
当路径是一个目录路径时,目录名称末尾中用于分隔文件名的分隔符可以省略。但是省略后会有歧义,如路径
C:/Users/Names
可能指的是Names
文件夹,也可能是一个名为Names
的文件,无法从路径上区分是目录还是文件。此时这个路径被识别成目录还是文件依赖于对其进行的操作。
② 如果一个路径中有文件名部分,那么此路径对应的是一个文件, 如C:/Users/Names/file.txt
。
1.1.1 卷号或驱动器
在文件资源管理器中,在此电脑目录下,我们可以看到各个驱动器,驱动器名称中带有的C:
,D:
为驱动器号,即常说的盘符。
1.1.2 目录名称
在文件资源管理器中,打开各种盘,我们可以看到里面是大量的文件夹和文件,文件夹中也嵌套包含着文件夹和文件,是一个层级结构,这个结构称为 目录树。
目录树示例如下:
打开一个文件,上方地址栏即为当前所在文件夹的路径,除去盘符(如下图中的E:)
后,其余部分称为目录名。下图中的目录名则为\ege\EGE20.08\include
我们再次看一下这个文件夹所在目录树的结构,可以看到,目录名由到达当前位置所路经的文件夹名称 组合而成,按进入的文件夹顺序拼接,中间用目录分隔符\
隔开。
windows系统的中目录分隔符默认用
\
表示,也可以用/
表示,由于在一些编程语言中(如C/C++),\
在字符串中代表转义,表示原来的\
字符要使用\\
,这样较为麻烦,并且其它系统如Linux可能识别不了\
,所以推荐使用/
。
1.1.3 文件名
文件名 由 主名 和 扩展名 两部分组成,主名和扩展名用英文句号.
隔开,即主名.扩展名
。扩展名用于表示文件的类型,文件主名为用户自定义的文件名称。
文件名的组成部分 | 作用 | 备注 |
---|---|---|
主名 | 用户自定义的文件名称 | |
扩展名 | 表示文件的类型 | 可省略 |
扩展名是可选的,文件名可以只有主名。
如下图所示,在图中的目录下有两个文件 index.htm
和 readme.md
,名称栏中显示的是文件夹和文件对应的名称,在 类型 栏可看到文件对应的文件类型(由扩展名确定)。
如果显示的文件名称里没有显示文件扩展名,只有文件主名,可以在 查看 菜单中,勾选文件扩展名。
文件扩展名表示文件的类型,系统是按照文件扩展名来确定文件的类型的,当用户要打开某个文件时,如果没有指定软件,那么系统会自动选用支持该文件格式的默认应用来打开该文件(常见的文件类型一般在系统中设置有默认应用)。
如果想用其它软件来打开某个文件,而不是使用默认应用,那么可以在右键菜单中选择 打开方式,然后在列出的软件列表中选择,如果列表中没有想要的软件,可以点击列表最下面的 选择其它应用 ,让系统找出所有关联到这个文件格式的软件。
如果列表中还是没找到对应的软件,可点击 更多应用 ,然后再点击 在这台电脑上查找其它应用,手动在文件资源管理器中选择软件的位置。
文件的扩展名可以随意命名,甚至可以没有。但是因为扩展名关联着文件的格式,当扩展名和文件类型对不上时(或者文件本身没有扩展名),有可能会因为无法识别文件格式从而导致文件不可用(系统找不到能打开扩展名对应类型的软件,或者指定软件打开时,软件无法根据内容识别其真正格式,造成数据错乱等)。(可以对文件重命名,重新把扩展名修改回去)
如果确定是文本文件,可以用 Notepad++,记事本等文本编辑器打开,这些软件会按照文本文件的格式来识别文件内容。
一些软件会根据文件内容识别文件格式,即使扩展名和文件实际的类型不符,也能正确打开。
以下为常见文件类型对应的扩展名:
文件类型 | 扩展名 |
---|---|
文本文件 | txt |
MP3音乐文件 | mp3 |
MP4视频文件 | mp4 |
JPEG格式图片文件 | jpg |
PNG格式图片文件 | png |
C源程序文件 | c |
C++源程序文件 | cpp |
C/C++头文件 | h |
1.2 当前目录 (Current directory)
在命令行中,可以看到在每行输入的开头都显示着一个路径,这个路径和输入之间用一个交互提示符 > 隔开。
这个路径即为命令行的当前目录,也叫 工作目录(Working directory) 或 当前路径(Current path)。
在windows 的命令行中,交互提示符为右尖括号
>
。
如下图所示,当前目录为 C:Users\19078
程序运行时,会把某个目录设定为程序的当前目录。如果在存储、读取文件时没有指定文件所在的目录,那么将认为文件是放置在当前目录中。
程序中当前目录的获取
在程序中,当前目录可以使用 <stdlib.h>
中的 getcwd()
函数,<Windows.h>
中的 GetCurrentDirectory()
函数等获取。
下面的程序会读取当前目录并输出到控制台窗口。
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
int main(int argc, char* argv[])
{
// 调用getcwd()函数获取,getcwd()被弃用,换成_getcwd()
//如果buffer传入NULL,则内部动态分配内存,需要调用者自行释放
char* cwd = _getcwd(NULL, MAX_PATH);
//使用 GetCurrentDirectory() 函数获取
TCHAR CurrentDirectory[MAX_PATH];
GetCurrentDirectory(MAX_PATH, CurrentDirectory);
//输出当前路径
puts(cwd);
//释放内存
free(cwd);
return 0;
}
1.3 切换盘符(驱动器跳转)
命令 | 示例 | |
---|---|---|
切换盘符 | 盘符: | 切换到D盘:D: |
如下所示,当前位于C盘,如果想要切换到其它盘符,可通过输入 盘符:
来进行切换。
例如,使用命令E:可切换到 E盘。如果想要再次切换回C盘,输入C:即可。
盘符由一个英文字母(不区分大小写)和一个冒号
:
组成。
切换到另一个盘符时,其实是跳转到对应驱动器下的当前目录(每个驱动器都有各自的当前目录),所以在上图可以看到,切换回C盘时,并不是跳转到 C:\
目录,而且跳转到C盘的当前目录中。
1.4 设置当前目录
当前目录有多种不同的含义,如命令行下的驱动器的当前目录、进程的当前目录等,作为路径的一个参考位置。
1.4.1 驱动器的当前目录
Windows下,每个驱动器都有自己的当前目录,跳转到其它驱动器后,其实跳转到其对应的当前目录上,如下图所示,跳转到其它驱动器后再跳转回C盘,依然是回到C盘的当前目录上。
在windows命令行下,可以使用 cd命令改变驱动器的当前目录,例如 cd 驱动器号:/目录名。如果目录路径中包含了驱动器号,那么会改变指定驱动器的当前目录,如果没有驱动器号,则改变当前驱动器的当前目录。
微软文档:cd 命令
cd 命令的全称是 Change Directory,也可以写作 chdir
,使用 cd 目录路径
命令只能设置对应跨盘符跳转,只能在当前盘符内跳转,要跳转到其它盘符的目录,需要先切换到对应盘符后,再用 cd
命令跳转。
下图中,当前目录位于C盘下。在命令 cd \Users\19078\Desktop 中,所要跳转的目标目录路径并没有包含驱动器号,那么意思就是设置当前驱动器的当前目录为 \Users\19078\Desktop
目录,设置后可以看到C盘的当前目录已经改变。再用 cd
命令设置E盘的当前目录,可以看到当前仍在C盘,切换到E盘后,可以看到E盘的当前目录已经修改成功。
如何查看各驱动器的当前目录
跳转到对应驱动器后就可以查看它的当前目录,除此之外,还可以用 cd 驱动器号: 命令进行查看,该命令会输出对应驱动器的当前目录。
1.4.2 进程的当前目录
启动一个程序时会开启一个进程,一个进程的当前目录默认是应用程序启动的目录,但启动时很有可能被更改。
例如,如果是在命令行下输入exe可执行文件的路径来启动应用程序,那么程序运行后,进程的当前目录是命令行的当前目录。
如果在文件资源管理器中打开可执行文件所在的目录,双击运行,此时进程的当前目录是可执行文件所在的目录。如果是经由其它文件搜索软件搜索后打开,当前目录需要看软件是如何调用的程序。
1.4.2.1 程序中设置当前目录
可以在程序中调用 SetCurrentDirectory()
函数来设置当前进程的当前目录。
一般是设置成exe可执行文件所在的位置。这个路径可以从
main()
函数的参数中获取。
#include <Windows.h>
SetCurrentDirectory("目录路径")
1.5 路径跳转
命令
路径跳转一共需要两步,分别是盘符:命令切换盘符 和 cd 目录路径设置当前目录。
① 使用 盘符:
命令切换盘符。
② 使用 cd 路径
命令跳转到对应路径上。
当目标目录位于当前驱动器时,不需要切换盘符。
操作示例
如下图所示,打开命令行后,当前目录默认为用户目录:
1. 输入cd Desktop 跳转到当前目录下的Desktop子目录中(这种路径写法我们称为相对路径)。
2. 输入 cd C:\Users 跳转到 C:\Users
目录下。
3. 输入 E: 切换到E盘。
4. 输入 cd E:\ege\EGE20.08 跳转到 E盘中的 E:\ege\EGE20.08
目录下
1.6 根目录 (Root directory)
根目录即直接位于驱动器中最顶层的目录,不被其它目录所包含,路径为 盘符:\
,如C盘根目录 C:\
, D盘根目录 D:\
。
要跳转到根目录下,输入 cd \ 即可。
1.7 当前目录与上一级目录的符号表示
命令行用句号 .
表示当前目录,用两个句号..
表示上一级目录。
目录 | 符号 |
---|---|
当前目录 | . |
上一级目录 | .. |
如下图所示,当前目录为 E:\ege\EGE20.08
,输入cd .. 后会跳转到当前目录的上一级目录,即E:\ege
这些符号可以插入到路径之中。
如E:\ege\EGE20.08\..
表示 E:\ege\EGE20.08
的上一级目录,即 E:\ege
,而E:\ege\..\ege\EGE20.08
则表示 E:\ege\
的上一级目录的ege\EGE20.08
子目录下,即 E:\ege\EGE20.08
。
.\ege
表示当前目录下的ege子目录。
1.8 分割路径(Split Path)
<stdlib.h>
头文件中的 _splitpath()
函数可以对一个路径进行分割,分割成驱动器号、目录名、文件主名和文件扩展名四个部分。
需要注意的是,为了区分一个路径是文件还是目录,目录路径中目录名后的目录分隔符不可省略,即使没有文件名,如 C:/Users/
。
微软参考文档:_splitpath, _wsplitpath
#include <stdlib.h>
const char* fullPath = "C:/dir/file.txt";
char drive[_MAX_DRIVE], dir[_MAX_DIR], fileName[_MAX_FNAME], ext[_MAX_EXT];
_splitpath(argv[0], drive, dir, fileName, ext);
1.9 构造路径
<stdlib.h>
头文件中的 _makepath()
函数可以将驱动器号,目录名,文件主名,文件扩展名这些其中几个部分组合成一个路径。
微软参考文档:_makepath、_wmakepath
#include <stdlib.h>
char path[_MAX_PATH];
_makepath(path, "盘符:", "目录名", "文件主名", "文件扩展名");
1.10 全路径(Full Path)
<stdlib.h>
中的 _fullpath
可以计算出一个路径对应的全路径。当给出的路径是相对路径时,函数会根据进程的当前路径来计算出对应的全路径。
微软参考文档:_fullpath, _wfullpath
#include <stdlib.h>
#include <stdio.h>
int main()
{
//内部自动分配内存,返回字符串首地址,需要调用者自行释放内存
char* fullPathName = _fullpath(NULL, "file.txt", MAX_PATH);
//输出
puts(fullPathName);
//释放内存
free(fullPathName);
return 0;
}
2. 绝对路径与相对路径
2.1 绝对路径与相对路径的区分
如果在一个路径中,包含了驱动器号(或卷号)和 目录名,并且目录名以目录分隔符(\
或/
) 开头,那么这个路径称为 绝对路径(Absolute path)。如果绝对路径中包含了文件名,那么则称其为 文件的绝对路径。
在一个文件系统中,绝对路径对应着一个明确、唯一且固定的文件或目录,也称为 完整路径 或 全路径。
如果一个路径未指定卷号或驱动器号, 或者目录名不以分隔符开头,那么这种路径称之相对路径。
相对路径无法直接确定一个唯一的且固定的文件或目录,随着当前目录或当前驱动器变化。
相对路径中,是否指定卷号或驱动器号,和目录名是否以分隔符开头,所得到的路径含义不同:
- 未指定驱动器号表示路径位于当前驱动器
- 目录名不以分隔符开头表示路径相对于当前目录,否则表示路径相对于驱动器根目录。
列表如下:
驱动器号 | 含义 | 目录名是否以目录分隔符开头 | 含义 |
---|---|---|---|
有 | 相对于指定的驱动器 | 是 | 相对于根目录 |
无 | 相对于当前的驱动器 | 否 | 相对于当前目录 |
路径示例
假设C盘的当前目录为
C:\Users
, E盘的当前目录为E:\ege
,切换到了E盘,即当前驱动器为E:
。
驱动器号是否指定 | 目录名是否以目录分隔符开头 | 含义 | 路径性质 | 示例 | 实际路径 |
---|---|---|---|---|---|
是 | 是 | 相对于指定驱动器的根目录,是明确、唯一且固定的 | 绝对路径 | C:\Users | C:\Users |
否 | 是 | 相对于当前驱动器的根目录 | 相对路径 | \Users | E:\Users |
是 | 否 | 相对于指定驱动器的当前目录 | 相对路径 | C:Users | C:\Users\Users |
否 | 否 | 相对于当前驱动器的当前目录 | 相对路径 | Users | E:\ege\Users |
2.2 相对路径的使用
相对路径指的是文件或目录与当前目录的相对位置,只要保证文件和当前目录的相对位置不变,那就能通过相对路径正确索引到对应的文件或目录,这带来的好处是文件不需要存放在固定的目录下。
将可执行文件及其所需的资源打包好后,由于可执行文件与其它资源文件相对位置没有改变,所以解压到计算机的任意位置后,运行可执行文件能够通过相对路径正确地读取到文件。
当前目录用.
表示,如果一个名为directory目录在当前目录下,那么这个目录的相对路径为 ./directory
,文件同理,若当前目录下有一个名为 file.txt
的文件,则文件的相对路径为 ./file.txt
。通常 ./
可以省略,所以可以直接简写为 directory
和 file.txt
。
2.3 文件路径的确定
2.3.1 绝对路径的确定
一个文件的绝对路径,可以打开其所在的文件夹,在地址栏查看其所在目录的路径,绝对路径由所在目录路径和文件名拼接而成,目录和文件名之间用分隔符隔开。
如下所示,ege.h
文件所在目录的路径为 E:\ege\EGE20.08\include
,则文件 ege.h
的绝对路径为 E:\ege\EGE20.08\include\ege.h
。
快捷键Shift + 鼠标右键,选择复制文件地址,即可复制文件的绝对路径。
还可以右键选择属性,在安全选项卡中查看。
2.3.2 相对路径的确定
相对路径首先需要知道当前目录。相对路径是相对于当前目录的位置,那么在运行程序时,这个当前目录是什么呢?
一般情况下,如果你直接到exe可执行文件所在的目录里 运行exe文件,那么当前目录就是 exe文件所在的目录。如果你通过集成开发环境调试运行程序, 那么这个当前目录就是工程中的源文件所在目录(因为在项目中创建源文件时,就是在项目的当前目录创建的)。
如果是其它地方启动的应用程序,则需要根据实际情况来分析,有可能是启动应用程序时当前所在目录,但不确定。
2.3.2.1 当前目录的获取
在不确定当前目录的情况下,可以通过在程序中加入一些读取当前目录的代码来查看。
#include <direct.h>
#include <stdio.h>
int main()
{
//获取当前路径,getcwd()在VS下被弃用,换成了_getcwd()
char* curWorkDirectory = _getcwd(NULL, MAX_PATH);
puts(curWorkDirectory);
free(curWorkDirectory);
return 0;
}
2.3.2.3 集成开发环境中调试运行
假设我们的程序是在集成开发环境中调试运行,那么当前目录应该是源文件所在的目录(如果源文件是在项目中新建的话)。在下面的图中,所圈的图片和 源文件main.cpp 在同一目录下, 那么用相对路径来表示这个图片那就是 ./girl.jpg
, 用一个英文句号来表示当前目录, 因为是在同一目录下,可以省略掉路径,最后简写成 girl.jpg
如果与源文件同目录下有个res文件夹, 而里面有张 girl2,jpg 的图片,那对应位置就是在当前目录的res文件夹中,表示成 ./res/girl2.jpg
, 当前路径部分可以省略,简写作 res/gir2.jpg
。
如果这个res文件是放在上一层目录中,对应文件的路径为 ../res/gril2.jpg
,如果是在上上层则为 ../../res/girl2.jpg
。
2.3.2.4 直接双击可执行文件运行程序
直接双击exe可执行文件运行程序时,当前目录就是可执行文件所在的目录。相对路径的计算方式不变。
在文件打包时,或者改变程序运行方式时(从集成开发环境中调试运行转到直接双击可执行文件运行),之前能读取到的文件突然无法读取了。出现这种情况时,如果文件位置没有移动,那很有可能是当前路径发生了改变,根据原来的相对路径是找不到文件的。可以通过以下方法解决:
- 可以根据相对路径,把用到的文件复制到对应的位置上。
- 或者通过改变当前目录的方式,移动可执行文件到合适的位置上。
2.4 使用相对路径无法正确读取到文件的情况
这种情况下如果排除了文件格式错误、库内部问题等因素,那很有可能是相对路径不正确。如果之前可以读取,换成某种方式运行程序就无法读取,那可能是当前目录发生了变化。
可以在程序将相对路径转成全路径并输出,然后和文件的全路径进行比较,以此来检查路径问题。
#include <stdlib.h>
#include <stdio.h>
int main()
{
char* fullPathName = _fullpath(NULL, "Path", MAX_PATH);
puts(fullPathName);
free(fullPathName);
return 0;
}
EGE专栏:EGE专栏