C#|C# 文件安全管理需要注意的

目录

  • 一.DotNet文件目录常用操作:
    • 1.文件常规操作:
    • 2.目录常规操作:
  • 二.DotNet文件目录访问管理:
    • 1.文件目录权限概述:
    • 2.文件共享操作实例:
  • 三.DotNet彻底删除文件操作:
    • 1.文件彻底删除概述:
    • 2.文件彻底删除实例:
  • 四.DotNet文件加密解密操作:
    • 1.Encrypt():文件加密操作。
    • 2.Decrypt():文件解密操作。
  • 五.总结:
    在实际的项目开发中,我们经常需要使用到文件的I/O操作,主要包含对文件的增改删查等操作,这些基本的操作我们都是很熟悉,但是较少的人去考虑文件的安全和操作的管理等方面,例如文件的访问权限管理,文件数据的彻底删除和数据的恢复等等,这一系列的操作需要我们对.NET的相关知识有一个深刻的学习。
    在本文章主要介绍文件和目录的一些基本操作,以及文件目录的权限和安全设置的相关内容。

    一.DotNet文件目录常用操作:
    提到文件的I/O操作,这个对于每一个开发者来说都不是陌生的事,因为这些操作是我们在项目开发过程中经常使用到的一些操作。那么在.NET中操作文件的类在System.IO命名空间下,一下介绍一下常见的I/O操作类:
    DiveInfo:提供了对逻辑磁盘的基本信息访问的途径。(只能查看信息,不能做任何修改。)
    System.Environment:用来枚举驱动器。(不能获取驱动器的属性)
    System.Management:.NET针对WMI调用。
    Directory和DircetoryInfo:用于操作目录。(前者为静态类,后者则须在实例化后调用,功能上相同)
    File和FileInfo:用于操作文件。(前者为静态类,后者须实例化后调用,功能上相同)
    以上介绍了一些文件的基本操作类,本次主要讲解目录和文件操作,一下给出文件和目录操作的一些基本方法:

    1.文件常规操作:

    (1).文件读写操作:
    /// /// 写文件/// /// 文件名/// 文件内容/// 指定文件编码protected void Write_Txt(string fileName, string content, string encoding){if (string.IsNullOrEmpty(fileName)){throw new ArgumentNullException(fileName); }if (string.IsNullOrEmpty(content)){throw new ArgumentNullException(content); }if (string.IsNullOrEmpty(encoding)){throw new ArgumentNullException(encoding); }var code = Encoding.GetEncoding(encoding); var htmlfilename = HttpContext.Current.Server.MapPath("Precious\\" + fileName + ".txt"); var str = content; var sw = StreamWriter.Null; try{using (sw = new StreamWriter(htmlfilename, false, code)){sw.Write(str); sw.Flush(); }}catch (IOException ioex){throw new IOException(ioex.Message); }catch (Exception ex){throw new Exception(ex.Message); }finally{sw.Close(); }}/// /// 读文件/// /// 文件路径/// 文件编码/// protected string Read_Txt(string filename, string encoding){if (string.IsNullOrEmpty(filename)){throw new ArgumentNullException(filename); }if (string.IsNullOrEmpty(encoding)){throw new ArgumentNullException(encoding); }var code = Encoding.GetEncoding(encoding); var temp = HttpContext.Current.Server.MapPath("Precious\\" + filename + ".txt"); var str = string.Empty; if (!System.IO.File.Exists(temp)) return str; var sr = StreamReader.Null; try{using (sr = new StreamReader(temp, code)){str = sr.ReadToEnd(); }}catch (IOException ioex){throw new IOException(ioex.Message); }catch (Exception ex){throw new Exception(ex.Message); }finally{sr.Close(); }return str; }

    (2).文件附加操作:
    /// /// 拷贝文件/// /// 原始文件/// 新文件路径public static void FileCoppy(string orignFile, string newFile){if (string.IsNullOrEmpty(orignFile)){throw new ArgumentException(orignFile); }if (string.IsNullOrEmpty(newFile)){throw new ArgumentException(newFile); }System.IO.File.Copy(orignFile, newFile, true); }/// /// 删除文件/// /// 路径public static void FileDel(string path){if (string.IsNullOrEmpty(path)){throw new ArgumentException(path); }System.IO.File.Delete(path); }/// /// 移动文件/// /// 原始路径/// 新路径public static void FileMove(string orignFile, string newFile){if (string.IsNullOrEmpty(orignFile)){throw new ArgumentException(orignFile); }if (string.IsNullOrEmpty(newFile)){throw new ArgumentException(newFile); }System.IO.File.Move(orignFile, newFile); }


    2.目录常规操作:
    /// /// 在当前目录下创建目录/// /// 当前目录/// 新目录public static void FolderCreate(string orignFolder, string newFloder){if (string.IsNullOrEmpty(orignFolder)){throw new ArgumentException(orignFolder); }if (string.IsNullOrEmpty(newFloder)){throw new ArgumentException(newFloder); }Directory.SetCurrentDirectory(orignFolder); Directory.CreateDirectory(newFloder); }/// /// 创建文件夹/// /// public static void FolderCreate(string path){if (string.IsNullOrEmpty(path)){throw new ArgumentException(path); }if (!Directory.Exists(path)){Directory.CreateDirectory(path); }}public static void FileCreate(string path){if (string.IsNullOrEmpty(path)){throw new ArgumentException(path); }var createFile = new FileInfo(path); if (createFile.Exists) return; var fs = createFile.Create(); fs.Close(); fs.Dispose(); }/// /// 递归删除文件夹目录及文件/// /// /// public static void DeleteFolder(string dir){if (string.IsNullOrEmpty(dir)){throw new ArgumentException(dir); }if (!Directory.Exists(dir)) return; foreach (var d in Directory.GetFileSystemEntries(dir)){if (System.IO.File.Exists(d)){//直接删除其中的文件 System.IO.File.Delete(d); }else{//递归删除子文件夹 DeleteFolder(d); }}//删除已空文件夹Directory.Delete(dir, true); }/// /// 指定文件夹下面的所有内容copy到目标文件夹下面/// /// 原始路径/// 目标文件夹public static void CopyDir(string srcPath, string aimPath){if (string.IsNullOrEmpty(srcPath)){throw new ArgumentNullException(srcPath); }if (string.IsNullOrEmpty(aimPath)){throw new ArgumentNullException(aimPath); }try{if (aimPath[aimPath.Length - 1] != Path.DirectorySeparatorChar){aimPath += Path.DirectorySeparatorChar; }if (!Directory.Exists(aimPath)){Directory.CreateDirectory(aimPath); }var fileList = Directory.GetFileSystemEntries(srcPath); foreach (var file in fileList){if (Directory.Exists(file)){CopyDir(file, aimPath + Path.GetFileName(file)); }else{System.IO.File.Copy(file, aimPath + Path.GetFileName(file), true); }}}catch (IOException ioex){throw new IOException(ioex.Message); }catch (Exception ee){throw new Exception(ee.ToString()); }}/// /// 获取指定文件夹下所有子目录及文件/// /// 详细路径public static string GetFoldAll(string path){if (string.IsNullOrEmpty(path)){throw new ArgumentNullException(path); }var str =string.Empty; var thisOne = new DirectoryInfo(path); str = ListTreeShow(thisOne, 0, str); return str; }/// /// 获取指定文件夹下所有子目录及文件函数/// /// 指定目录/// 默认起始值,调用时,一般为0/// 用于迭加的传入值,一般为空/// public static string ListTreeShow(DirectoryInfo theDir, int nLevel, string rn){if (theDir == null){throw new ArgumentNullException("theDir"); }//获得目录DirectoryInfo[] subDirectories = theDir.GetDirectories(); foreach (DirectoryInfo dirinfo in subDirectories){if (nLevel == 0){rn += "├"; }else{var s =string.Empty; for (int i = 1; i <= nLevel; i++){s += "│  "; }rn += s + "├"; }rn += "" + dirinfo.Name + "
    "; //目录下的文件var fileInfo = dirinfo.GetFiles(); foreach (FileInfo fInfo in fileInfo){if (nLevel == 0){rn += "│  ├"; }else{var f = string.Empty; for (int i = 1; i <= nLevel; i++){f += "│  "; }rn += f + "│  ├"; }rn += fInfo.Name.ToString() + "
    "; }rn = ListTreeShow(dirinfo, nLevel + 1, rn); }return rn; }/// /// 获取指定文件夹下所有子目录及文件(下拉框形)/// /// 详细路径///下拉列表名称///默认选择模板名称public static string GetFoldAll(string path, string dropName, string tplPath){if (string.IsNullOrEmpty(path)){throw new ArgumentNullException(path); }if (string.IsNullOrEmpty(tplPath)){throw new ArgumentNullException(tplPath); }var strDrop = ""; var str =string.Empty; DirectoryInfo thisOne = new DirectoryInfo(path); str = ListTreeShow(thisOne, 0, str, tplPath); return strDrop + str + ""; }/// /// 获取指定文件夹下所有子目录及文件函数/// /// 指定目录/// 默认起始值,调用时,一般为0/// 用于迭加的传入值,一般为空/// 默认选择模板名称/// public static string ListTreeShow(DirectoryInfo theDir, int nLevel, string rn, string tplPath){if (theDir == null){throw new ArgumentNullException("theDir"); }//获得目录DirectoryInfo[] subDirectories = theDir.GetDirectories(); foreach (DirectoryInfo dirinfo in subDirectories){rn += "


    二.DotNet文件目录访问管理:

    1.文件目录权限概述:

    提到权限这个概念,这对于每一个开发者都是再熟悉不过的,因为我们在开发项目时,都会考虑用户权限管理等等,但是文件的权限操作呢?这里我们就简单的介绍一下.NET中对文件访问权限的访问和设置。文件权限中的访问控制列表: 自由访问控制列表(DACL):Microsoft Windows NT和更高版本用于保护资源的机制;系统访问控制列表(SACL):一种控制与资源关联的审核消息的机制。System.Security.AccessControl命名空间通过一些类提供对访问控制列表的访问。DiectorySecurity:该类指定目录的访问控制和审核安全。指定系统目录的访问权限以及访问尝试的审核方式。FileSecurity:该类指定系统文件的访问权限以及如何审核访问尝试。
    下面介绍一下文件权限操作的类和方法:
    (1).FileStream类GetAccessControl():检索文件的安全对象:
    [SecuritySafeCritical]public FileSecurity GetAccessControl(){ if (this._handle.IsClosed) {__Error.FileNotOpen(); } return new FileSecurity(this._handle, this._fileName, AccessControlSections.Group | AccessControlSections.Owner | AccessControlSections.Access); }

    [SecurityCritical, SecurityPermission(SecurityAction.Assert, UnmanagedCode=true)]internal FileSecurity(SafeFileHandle handle, string fullPath, AccessControlSections includeSections) : base(false, handle, includeSections, false){ if (fullPath != null) {new FileIOPermission(FileIOPermissionAccess.NoAccess, AccessControlActions.View, fullPath).Demand(); } else {new FileIOPermission(PermissionState.Unrestricted).Demand(); }}

    (2).FileStream类SetAccessControl():保存设置。
    [SecuritySafeCritical]public void SetAccessControl(FileSecurity fileSecurity){ if (fileSecurity == null) {throw new ArgumentNullException("fileSecurity"); } if (this._handle.IsClosed) {__Error.FileNotOpen(); } fileSecurity.Persist(this._handle, this._fileName); }


    2.文件共享操作实例:
    /// /// 共享文档操作 /// public class FileSharingOperationHelper {public static bool ConnectState(string path){if (string.IsNullOrEmpty(path)){throw new ArgumentNullException(path); }return ConnectState(path, "", ""); }/// /// 连接远程共享文件夹/// /// 远程共享文件夹的路径/// 用户名/// 密码/// public static bool ConnectState(string path, string userName, string passWord){var proc = new Process(); try{proc.StartInfo.FileName = "cmd.exe"; proc.StartInfo.UseShellExecute = false; proc.StartInfo.RedirectStandardInput = true; proc.StartInfo.RedirectStandardOutput = true; proc.StartInfo.RedirectStandardError = true; proc.StartInfo.CreateNoWindow = true; proc.Start(); var dosLine = "net use " + path + " " + passWord + " /user:" + userName; proc.StandardInput.WriteLine(dosLine); proc.StandardInput.WriteLine("exit"); while (!proc.HasExited){proc.WaitForExit(1000); }var errormsg = proc.StandardError.ReadToEnd(); proc.StandardError.Close(); if (!string.IsNullOrEmpty(errormsg)){throw new Exception(errormsg); }}catch (Exception ex){throw new Exception(ex.Message); }finally{proc.Close(); proc.Dispose(); }return true; }/// /// 向远程文件夹保存本地内容,或者从远程文件夹下载文件到本地/// /// 要保存的文件的路径,如果保存文件到共享文件夹,这个路径就是本地文件路径如:@"D:\1.avi"/// 【C#|C# 文件安全管理需要注意的】保存文件的路径,不含名称及扩展名/// 保存文件的名称以及扩展名public static void Transport(string src, string dst, string fileName){if (string.IsNullOrEmpty(src)){throw new ArgumentNullException(src); }if (string.IsNullOrEmpty(dst)){throw new ArgumentNullException(dst); }if (string.IsNullOrEmpty(fileName)){throw new ArgumentNullException(fileName); }FileStream inFileStream = null; FileStream outFileStream = null; try{inFileStream = new FileStream(src, FileMode.Open); if (!Directory.Exists(dst)){Directory.CreateDirectory(dst); }dst = dst + fileName; outFileStream = new FileStream(dst, FileMode.OpenOrCreate); var buf = new byte[inFileStream.Length]; int byteCount; while ((byteCount = inFileStream.Read(buf, 0, buf.Length)) > 0){outFileStream.Write(buf, 0, byteCount); }}catch (IOException ioex){throw new IOException(ioex.Message); }catch (Exception ex){throw new Exception(ex.Message); }finally{if (inFileStream != null){inFileStream.Flush(); inFileStream.Close(); }if (outFileStream != null){outFileStream.Flush(); outFileStream.Close(); }}} }

    文件权限的规则:容器的访问规则可能被配置为不仅应用于对象本身,而且还应用于它的子对象、子容器或这两者。每个访问规则不是显示的就是继承的。DACL可以有对象的所有者任意修改,还可以由所有者已经给予其梗概DACL权限的任何更改。对象的安全描述包含另一个规则列表,称为系统访问权限列表(SACL),该列表将控制系统对对象执行哪个类型的审核。审核是一种具有安全敏感性的操作。在windows中,审核只能由本地安全机构(LSA)生成,LSA是唯一允许向安全事件日志中写入的组件。

    三.DotNet彻底删除文件操作:

    1.文件彻底删除概述:

    看到文件删除,可能有人会问,前面不是已经介绍过文件的删除操作吗?为什么这里还需要详细的介绍。不错,上面的确介绍了文件和目录的删除方法,但是这里是介绍如何彻底的删除文件。我们常规的删除文件和文件格式化,一般是可以被恢复的。我们在操作删除的时候,只是将文件的索引给删除了,并没有删除实际的内容。文件的索引记录了文件在磁盘中的位置信息,当执行删除操作时,只是从文件分配聊表中删除了目录。
    那么可能会有人问,怎么讲文件彻底的删除呢?文件的粉碎,其实就是在删除文件分配列表的同时,把文件在磁盘上占用的所有扇区数据置为0。
    在.NET中提供了两种文件彻底的方法:
    (1).调用系统API来完成这样的“粉碎”操作。
    (2).在删除文件之前先删除文件的所有内容,然后在执行删除操作,被称为“假粉碎”。(此方法可以被人恢复文件,但是恢复的数据只是文件中的0)
    为了文件安全,可以采用多轮粉碎的方式:第一轮,通过文件操作Windows API,找到原始文件的铭文在存储器上所载区域,逐字符逐位进行完全填充,全部填充为0。第二轮,通过磁盘操作WindowsAPI找到原始文件或目录在FAT表中的位置,将原始文件或目录在FAT表中项清零。第三轮,通过磁盘操作WindowsAPI,找到原始文件或目录在备份FAT表的位置,将原始文件或目录在备份FAT表中的表项清零。

    2.文件彻底删除实例:
    /// /// 粉碎文件操作 /// public class KillFileHelper {/// /// 强力粉碎文件,文件如果被打开,很难粉碎/// /// 文件全路径/// 删除次数/// 随机数据填充文件,默认true/// 空白填充文件,默认false/// true:粉碎成功,false:粉碎失败public static bool KillFile(string filename, int deleteCount, bool randomData = https://www.it610.com/article/true, bool blanks = false){if (string.IsNullOrEmpty(filename)){throw new ArgumentNullException(filename); }const int bufferLength = 1024000; var ret = true; try{using (var stream = new FileStream(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)){var f = new FileInfo(filename); var count = f.Length; long offset = 0; var rowDataBuffer = new byte[bufferLength]; while (count>= 0){var iNumOfDataRead = stream.Read(rowDataBuffer, 0, bufferLength); if (iNumOfDataRead == 0){break; }if (randomData){var randombyte = new Random(); randombyte.NextBytes(rowDataBuffer); }else if (blanks){for (var i = 0; i < iNumOfDataRead; i++)rowDataBuffer[i] = 0; }else{for (var i = 0; i < iNumOfDataRead; i++)rowDataBuffer[i] = Convert.ToByte(Convert.ToChar(deleteCount)); }// 写新内容到文件。for (var i = 0; i < deleteCount; i++){stream.Seek(offset, SeekOrigin.Begin); stream.Write(rowDataBuffer, 0, iNumOfDataRead); }offset += iNumOfDataRead; count -= iNumOfDataRead; }}//每一个文件名字符代替随机数从0到9。var newName = ""; do{var random = new Random(); var cleanName = Path.GetFileName(filename); var dirName = Path.GetDirectoryName(filename); var iMoreRandomLetters = random.Next(9); // 为了更安全,不要只使用原文件名的大小,添加一些随机字母。for (var i = 0; i < cleanName.Length + iMoreRandomLetters; i++){newName += random.Next(9).ToString(); }newName = dirName + "\\" + newName; } while (File.Exists(newName)); // 重命名文件的新的随机的名字。File.Move(filename, newName); File.Delete(newName); }catch{//可能其他原因删除失败了,使用我们自己的方法强制删除var matchPattern = @"(?<=\s+pid:\s+)\b(\d+)\b(?=\s+)"; try{//要检查被那个进程占用的文件var fileName = filename; var tool = new Process { StartInfo = { FileName = "handle.exe", Arguments = fileName + " /accepteula", UseShellExecute = false, RedirectStandardOutput = true } }; tool.Start(); tool.WaitForExit(); var outputTool = tool.StandardOutput.ReadToEnd(); foreach (Match match in Regex.Matches(outputTool, matchPattern)){//结束掉所有正在使用这个文件的程序Process.GetProcessById(int.Parse(match.Value)).Kill(); }File.Delete(fileName); }catch{ret = false; }}return ret; } }


    四.DotNet文件加密解密操作:
    上面介绍了文件的基本操作,文件权限操作,文件的删除操作,最后介绍一下文件的加密和解密操作。File和FileInfo类对文件加密进行了进一步的封装,提供了Encrypt和Decrypt方法用来对文件加密和解密。这两种方法要求文件系统必须为NFTS系统,对操作系统版本也要求必须是NT以上版本,使用该方法加密的文件,必须由同一用户才能进行解密。
    具体看一下该方法的实现代码:

    1.Encrypt():文件加密操作。
    [SecuritySafeCritical]public static void Encrypt(string path){ if (path == null) {throw new ArgumentNullException("path"); } string fullPathInternal = Path.GetFullPathInternal(path); new FileIOPermission(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, new string[] { fullPathInternal }, false, false).Demand(); if (!Win32Native.EncryptFile(fullPathInternal)) {int errorCode = Marshal.GetLastWin32Error(); if (errorCode == 5){DriveInfo info = new DriveInfo(Path.GetPathRoot(fullPathInternal)); if (!string.Equals("NTFS", info.DriveFormat)){throw new NotSupportedException(Environment.GetResourceString("NotSupported_EncryptionNeedsNTFS")); }}__Error.WinIOError(errorCode, fullPathInternal); }}


    2.Decrypt():文件解密操作。
    [SecuritySafeCritical]public static void Decrypt(string path){ if (path == null) {throw new ArgumentNullException("path"); } string fullPathInternal = Path.GetFullPathInternal(path); new FileIOPermission(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, new string[] { fullPathInternal }, false, false).Demand(); if (!Win32Native.DecryptFile(fullPathInternal, 0)) {int errorCode = Marshal.GetLastWin32Error(); if (errorCode == 5){DriveInfo info = new DriveInfo(Path.GetPathRoot(fullPathInternal)); if (!string.Equals("NTFS", info.DriveFormat)){throw new NotSupportedException(Environment.GetResourceString("NotSupported_EncryptionNeedsNTFS")); }}__Error.WinIOError(errorCode, fullPathInternal); }}


    五.总结:
    以上简单的介绍了文件的操作和文件的权限管理方法,如果需要更加深入的了解这些操作方法,可以查看msdn,或者查看.NET的“垫片”,查看相应的接口。在当代社会中,数据安全和文件安全都是很重要的,我们应该更加深入的去学习安全知识,提高系统的稳定性。
    以上就是C# 文件安全管理需要注意的的详细内容,更多关于C# 文件安全管理的资料请关注脚本之家其它相关文章!

      推荐阅读