完成一个函数复制文件夹,将源文件夹(strSrcDir)的文件复制到目标文件夹(strDestDir)。
为了简化问题,限定如下:
一,如果参数错误,可以崩溃,但不能损坏源文件。
简单实现:
依次复制各文件,如果目标文件存在,则先删除。
这个实现有个严重的缺陷但触发几率低的缺陷。当源文件夹和目标文件夹相同时,会把源文件夹清空。可能有人说源文件夹和目标文件夹几乎不会完全相同。以下情况很常见:
一,源文件夹和目标文件夹都是配置的,在两个不同的配置界面。
二,一个文件夹是按某种规则生成,一个文件夹是配置的。
解决方法:
如果源文件和目标文件夹相同,则直接返回。
具体方案:
一,文件夹支持大小写,但不区分大小写。统一大小写。
二,文件夹包括/和\,效果完全一样。统一成/
三,可能包括父目录..和本目录.。正确解析这两个符号。
四,可能有多余的/和\。删除多余的/和\。
五,相对目录。转成绝对目录
六,带盘符的相对目录。转成绝对目录
C#的以下代码完美解决了二三四五六。
System.IO.FileInfo info = new FileInfo("c:\\aa\\..\\a.txt"); Console.WriteLine(info.DirectoryName);
问题扩展:源文件夹是目标文件夹的子文件或目标文件是源文件夹的子孙有问题么?
源目录: c:\ 目标目录:c:\a
先复制 c:\1.txt 到 c:\a\1.txt ,此操作损坏了c:\a\1.txt
再复制 c:\a\1.txt 到 c:\a\a\1.txt 由于源文件是损坏的,所以复制后的文件一定是损坏的。
源目录: c:\a 目标目录:c:
复制 c:\a\a\1.txt 到 c:\a\1.txt 此操作损坏了c:\a\1.txt
复制 c:\a\1.txt 到c:\1.txt,由于源文件是损坏的,所以复制后的文件一定是损坏的。
无论源文件夹还是目标文件夹是子孙目录,都可能损坏源文件,并复制错误的数据。
如果源文件夹是祖先目录,目标文件夹是子孙目录,如果子孙目录被修改,则祖父目录必定被修改。所以这种情况,必定出错。
如果源文件夹是子孙目录,目标文件夹是祖先目录,则有可能不出错。比如:源目录:c:\a 目标目录 c:\ ,c:\a 只有一个文件1.txt,没文件夹。
简单解决方案:
如果源文件夹和目标文件相同直接返回成功。
如果源文件夹和目标文件相互为子孙目录,直接返回失败。
复杂解决方案:
如果源文件夹容许增加文件,互为子文件夹,也可正常操作。
假定第i个,j个文件 相对于源目录的相对文件名为subPath[i],subPath[j],i<j
strSrcPath+subPath[i]=> strDstPath + subPath[i]
strSrcPath+subPath[j]=> strDstPath + subPath[j]
如果strDstPath + subPath[i] 和 strSrcPath+subPath[j] 相等,文件就会损坏。 避免相等,就可以避免损坏。
避免方法:
如果归一化后的strDestPath的长度比归一化后的strSrcPath短,则短的subPath放到前面,既subPath[i]比subPath[j]短,两个较短的字符串起来一定比两个较长的字符串短。
如果归一化后的strDestPath的长度比归一化后的strSrcPath长,则长的subPath放到前面。
最终采用:简单版。理由:
一,复杂版的好处太少,复杂度增加多。复杂度是万恶之源。
二,证明过程不一定是对的。
三,证明过程不一定能快速理解,降低可维护性。
源文件夹和目标文件相同直接返回成功,可能让调用者出错,比如: 复制文件夹成功后,删除源文件夹。