zoukankan      html  css  js  c++  java
  • C# 解锁从互联网下载的需要右键属性“解除锁定”的文件

    一、代码实现

    1、AlternateDataStream.cs

    using System;
    using System.IO;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Text;
    
    namespace FileUnlockOnNtfsTool.Common
    {
        /// <summary>
        /// NTFS文件系统,文件替代流操作方法类
        /// </summary>
        internal static class AlternateDataStream
        {
            public const int _MaxPath = 256;
            private const string _LongPathPrefix = @"\?";
            public const char _StreamSeparator = ':';
    
            private static readonly char[] InvalidStreamNameChars = Path.GetInvalidFileNameChars().Where(c => c < 1 || c > 31).ToArray();
    
            [DllImport("kernel32.dll", CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)]
            private static extern int FormatMessage(
                int dwFlags,
                IntPtr lpSource,
                int dwMessageId,
                int dwLanguageId,
                StringBuilder lpBuffer,
                int nSize,
                IntPtr vaListArguments);
    
            [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
            private static extern int GetFileAttributes(string fileName);
    
            [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool DeleteFile(string name);
    
            /// <summary>
            /// 建立流路径
            /// </summary>
            /// <param name="filePath">文件全名</param>
            /// <param name="streamName">流名称</param>
            /// <returns></returns>
            public static string BuildStreamPath(string filePath, string streamName)
            {
                if (string.IsNullOrEmpty(filePath))
                    return string.Empty;
    
                string result = filePath;
                int length = result.Length;
                while (0 < length && '\' == result[length - 1])
                {
                    length--;
                }
    
                if (length != result.Length)
                {
                    result = 0 == length ? "." : result.Substring(0, length);
                }
    
                result += _StreamSeparator + streamName + _StreamSeparator + "$DATA";
    
                if (_MaxPath <= result.Length && !result.StartsWith(_LongPathPrefix))
                {
                    result = _LongPathPrefix + result;
                }
    
                return result;
            }
    
            /// <summary>
            /// 校验是否有效流名称
            /// </summary>
            /// <param name="streamName"></param>
            public static bool ValidateStreamName(string streamName)
            {
                if (!string.IsNullOrEmpty(streamName) && -1 != streamName.IndexOfAny(InvalidStreamNameChars))
                    return false;
    
                return true;
            }
    
            public static bool FileExists(string name)
            {
                return -1 != SafeGetFileAttributes(name);
            }
    
            private static int SafeGetFileAttributes(string name)
            {
                if (string.IsNullOrEmpty(name))
                    throw new ArgumentNullException("流路径不能为空");
    
                return GetFileAttributes(name);
            }
    
            public static bool SafeDeleteFile(string name)
            {
                if (string.IsNullOrEmpty(name))
                    throw new ArgumentNullException("流路径不能为空");
    
                return DeleteFile(name);
            }
        }
    }
    View Code

    2、FileSystem.cs

    using System;
    using System.IO;
    
    namespace FileUnlockOnNtfsTool.Common
    {
        /// <summary>
        /// FileInfo扩展方法
        /// </summary>
        public static class FileSystem
        {
            /// <summary>
            /// 指定替代流在文件中是否存在
            /// </summary>
            /// <param name="file"></param>
            /// <param name="sStreamName"></param>
            /// <returns></returns>
            public static bool AlternateDataStreamExists(this FileSystemInfo file, string sStreamName, out string sStreamPath)
            {
                if (null == file)
                    throw new ArgumentNullException("文件不能为空");
    
                if (!AlternateDataStream.ValidateStreamName(sStreamName))
                    throw new ArgumentException("流名称存在无效字符");
    
                sStreamPath = AlternateDataStream.BuildStreamPath(file.FullName, sStreamName);
                if (string.IsNullOrWhiteSpace(sStreamPath))
                    throw new ArgumentException("建立流路径失败,值不能为空");
    
                return AlternateDataStream.FileExists(sStreamPath);
            }
    
            /// <summary>
            /// 删除指定替代流
            /// </summary>
            /// <param name="file"></param>
            /// <param name="sStreamName"></param>
            /// <returns></returns>
            public static bool DeleteAlternateDataStream(this FileSystemInfo file, string sStreamName)
            {
                string sStreamPath = "";
                if (!AlternateDataStreamExists(file, sStreamName, out sStreamPath))
                    throw new ArgumentException("指定流不存在");
    
                return AlternateDataStream.SafeDeleteFile(sStreamPath);
            }
        }
    }
    View Code

    3、使用

    private void btnCheck_Click(object sender, EventArgs e)
            {
                FileInfo file = new FileInfo(txtFile.Text);
                try
                {
                    if (!file.Exists)
                    {
                        MessageBox.Show("文件不存在");
                        return;
                    }
    
                    string sStreamPath = "";
                    if (!file.AlternateDataStreamExists(_sZoneId, out sStreamPath))
                    {
                        MessageBox.Show("文件未锁定");
                        return;
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("文件安全锁验证异常:" + ex.Message);
                }
    
                try
                {
                    if (DialogResult.Yes != MessageBox.Show("文件有安全锁!
    是否解除锁定?", "消息", MessageBoxButtons.YesNo, MessageBoxIcon.Information, MessageBoxDefaultButton.Button2))
                        return;
    
                    if (file.DeleteAlternateDataStream(_sZoneId))
                        MessageBox.Show("解锁成功!");
                    else
                        MessageBox.Show("解锁失败");
                }
                catch (Exception ex)
                {
                    MessageBox.Show("解锁异常:" + ex.Message);
                }
            }
    View Code

    二、扩展阅读

    1、甚么是 “alternative data-streams” ?

          Since NT 3.1, the NTFS file system has supported multiple data-streams for files. There has never been built-in support for viewing or manipulating these additional streams, but the Windows API functions include support for them with a special file syntax: Filename.ext:StreamName. Even Win9x machines can access the alternative data streams of files on any NTFS volume they have access to, e.g., through a mapped drive. Because the Scripting.FileSystemObject and many other libraries call the CreateFile API behind the scenes, even scripts have been able to access alternative streams quite easily (although enumerating the existing streams has always been tricky).

    2、为什么非要用Win32API,原生C#实现不了功能么?

          In .NET, however, it seems someone decided to add some checking to the format of filenames. If you attempt to open a FileStream on an alternative stream, you will get a "Path Format not supported" exception. I have been unable to find any class in the CLR that provides support for alternative data streams, so I decided to roll my own.

    借鉴出处:https://www.codeproject.com/Articles/2670/Accessing-alternative-data-streams-of-files-on-an

  • 相关阅读:
    “零接触”新需求,如何快速实现体温检测数字化管控方案?
    AR公共安全及应急指挥中的应用 | TVP思享
    当模板方法遇到了委托函数,你的代码又可以精简了
    为什么要用内插字符串代替string.format
    如何让多个不同类型的后端网站用一个nginx进行反向代理实际场景分析
    8天入门docker系列 —— 第八天 让程序跑在swarm集群上
    8天入门docker系列 —— 第七天 让你的container实现跨主机访问
    8天入门docker系列 —— 第六天 搭建自己的私有镜像仓库Registry
    8天入门docker系列 —— 第五天 使用aspnetcore小案例熟悉容器互联和docker-compose一键部署
    8天入门docker系列 —— 第四天 使用aspnetcore小案例熟悉端口映射和挂载目录
  • 原文地址:https://www.cnblogs.com/seanyan/p/14331489.html
Copyright © 2011-2022 走看看