1.Linux下创建文件
在涉及文件操作的时候,就经常要考虑某个文件已经建了没有。比如说在导出数据的时候。在Linux下,要建立某个文件,它的上级目录一定要已经存在了。
比如说,如果想创建一个"/tmp/aaa/bbb/ccc/ddd/data.xml"的文件,必须先创建"/tmp/aaa/bbb/ccc/ddd",步骤如下:
1)如果"/tmp"目录不存在,创建"/tmp"。
2)如果"/tmp/aaa"目录不存在,创建"/tmp/aaa"。
3)如果"/tmp/aaa/bbb"目录不存在,创建"/tmp/aaa/bbb"。
4)如果"/tmp/aaa/bbb/ccc"目录不存在,创建"/tmp/aaa/bbb/ccc"。
5)如果"/tmp/aaa/bbb/ccc/ddd"目录不存在,创建"/tmp/aaa/bbb/ccc/ddd"。
6)创建"/tmp/aaa/bbb/ccc/ddd/data.xml"文件。
2.MKDIR 函数
所以说就想写一个函数去检测所给的文件名所在的目录是否已经创建,也就是说要检测这个文件所在目录的所有上级目录创建了没有。比如说“/tmp/aaa/bbb/ccc/ddd/data.xml ”文件,它的上级目录分别是
“/tmp”,"/tmp/aaa","/tmp/aaa/bbb","/tmp/aaa/bbb/ccc","/tmp/aaa/bbb/ccc/ddd"
要检测这些目录都创建了没有,如果没有创建,就自动创建。我们把这个函数叫做MKDIR。
3. MKDIR函数的声明
3.1 返回值
返回值可以设置为 bool 型,如果文件创建失败就返回false
3.2 函数的参数
检测文件或目录是否已经创建,所以在调用这个函数的时候要传文件或目录名,这是第一个参数。
这个函数是检测文件或者目录,也就是说要告诉这个函数检测的是文件名还是目录名,文件名和目录名要有各自的标识。如果没有标识会发生什么事。这是第二个参数。
比如说,"/tmp/aaa/bbb/ccc/ddd/data.xml"这是一个文件名,但是我告诉函数这是一个目录,那么这个函数就会创建名为 "/tmp/aaa/bbb/ccc/ddd/data.xml"的目录。
3.3 函数体
(1)拆分字符串
这个函数要逐级检测目录是否已经创建,文件名或目录名是一个字符串,所以遇到的第一个问题就是将字符串拆分,也就是把各级的目录名拆分出来。怎么拆分呢,只要知道每级目录的字符串长度就可以利用 strncpy() 函数拆分出来。
拿上面的例子来说:"/tmp/aaa/bbb",第一级目录是 /temp,那么我要算出这级目录的长度,我先找到 /temp/ 中和 p 紧挨着的 ‘/’,然后算出’/'前面有几个字符,接着就拆分出来。
问题又来了,怎么算出前面有几个字符,怎么找’/’,通常用的方法就是做对比。怎么做对比?为了方便解释把"/tmp/aaa/bbb" 叫做 filename
因为 filename[0]==’/’ 了,所以我们从 filename[1] 开始和 ‘/’ 做对比,可以这样写 if ( filename[1] != ‘/’ )
怎么算出字符数呢,这里巧了,当 filename[1] != ‘/’ 时,filename[ii] 的ii就加1(ii 就记录了有几个字符),继续比较下一个字符是否是 ‘/’,如果是 ‘/’ 就相当于找到了这一级目录的结束标记,也就找到这级目录,长度截止到 ‘/’ 。。当 filename[ii] == ‘/’ 时,就相当于找到了这一级目录,就把这级目录拆分出来检测。如果这级目录已经创建了,就继续拆分出下一级的目录。
(2)检测是否已经创建
目录是否已经创建,使用C语言提供的库函数 access(),如果没有创建就使用mkdir()创建。
4. MKDIR函数实现
// pathorfilename:绝对路径的文件名或目录名。
// bisfilename:说明pathorfilename的类型,true-pathorfilename是文件名,否则是目录名,缺省值为true。
// 返回值:true-创建成功,false-创建失败,如果返回失败,原因有大概有三种情况:1)权限不足; 2)pathorfilename参数不是合法的文件名或目录名;3)磁盘空间不足。
bool MKDIR(const char *filename,bool bisfilename)
{
// 检查目录是否存在,如果不存在,逐级创建子目录
char strPathName[301]; //暂时存放某级文件或目录名
int ilen=strlen(filename);
for (int ii=1; ii<ilen;ii++)
{
if (filename[ii] != '/') continue;
memset(strPathName,0,sizeof(strPathName)); //每次都要初始化,因为ii是一直增加的
// 每次赋值给strpathName是复制前ii个,所以要把前面的清空
// 比如说目录为/tmp/aaa/bbb 第一次复制 /tmp
// 第二次复制 /tmp/aaa,前面的目录级也会被复制,所以要清空strPathName前面存放的目录级
strncpy(strPathName,filename,ii); //复制给strPathName
if (access(strPathName,F_OK) == 0) continue;// 如果已经创建,就继续拆分下一级目录
if (mkdir(strPathName,0755) != 0) return false;//没有创建,就创建
}
if (bisfilename==false)//传的是目录名
{
if (access(filename,F_OK) != 0)
{
if (mkdir(filename,0755) != 0) return false;
}
}
return true;
}
5.测试代码
5.1 测试1
标志为false
int main(int argc,char *argv[])
{
MKDIR("/tmp/aaa/bbb/ccc/ddd/data.txt",false);
return 0;
}
测试结果
5.2 测试2
传的是文件名,标志为true
测试代码
int main(int argc,char *argv[])
{
MKDIR("/tmp/aaa/bbb/ccc/dddd/data.txt",true);
return 0;
}
结果