文件名以句号结尾并使用FileInfo C#

文件名以句号结尾并使用FileInfo C#,c#,file-exists,system.io.fileinfo,C#,File Exists,System.io.fileinfo,我遇到了一个问题,FileInfo无法看到名称末尾包含句点的文件。我知道Windows禁止以这种方式命名文件,但这些数据来自不同的操作系统 我可以使用命令行在Windows中创建问题文件: echo "test" > "\\?\C:\Test\BadFileName." 这是我用来测试文件的代码: DateTime origAccessDate; DateTime OrigCreateDate; long sizeBytes; string path = @"\\?\C:\Test\B

我遇到了一个问题,FileInfo无法看到名称末尾包含句点的文件。我知道Windows禁止以这种方式命名文件,但这些数据来自不同的操作系统

我可以使用命令行在Windows中创建问题文件:

echo "test" > "\\?\C:\Test\BadFileName."
这是我用来测试文件的代码:

DateTime origAccessDate;
DateTime OrigCreateDate;
long sizeBytes;

string path = @"\\?\C:\Test\BadFileName.";
FileInfo fi = new FileInfo(path);

try
{
     origAccessDate = fi.LastAccessTime;
     OrigCreateDate = fi.CreationTime;
     sizeBytes = fi.Length;
}
catch (Exception ex)
{
     MessageBox.Show(ex.Message);
}

在路径上调用FileInfo时会出现问题。Exists属性为false,即使您可以复制/粘贴路径以确认其有效性。目标不是为了读取而重命名文件,而是就地读取(原样)。

由于这显然是一种不受支持的情况,我怀疑不使用一些低级文件访问就可以完成

您可以尝试做的是删除
FileInfo
,然后继续
File.Exists(路径)
File.ReadAllBytes(路径)
。 这些措施或许可以绕过这个问题

使用SafeFileHandle访问文件

以下内容未经测试

创建
UnmanagedFileLoader
(下面的代码,取自)的实例允许您创建
SafeFileHandle
对象,该对象可以通过以下方式传递给
FileStream
构造函数:

UnmanagedFileLoader ufl = new UnmanagedFileLoader(path);
FileStream fs = new FileStream(ufl.Handle, FileMode.Open);
注意:记得调用
ufl.Handle.Dispose()

我们可以说,这将使您能够更直接地访问该文件,因此,您可以使用Windows提供的有效文件名

非托管leLoader代码

使用Windows API访问文件日期

下面取自的
GetFileTimeSample
类使用另一个Windows API调用,特别是
GetFileTime
。 此实现只是一个示例,您肯定能够对其进行调整以仅获取所需的日期。以当前形式,它将输出所有三个日期

用法:

DateTime fileDateCreated;
DateTime fileDateAccessed;
DateTime fileDateModified;
GetFileTimeSample.GetFileTimes(path, out fileDateCreated, out fileDateAccessed, out fileDateModified);
由于C#7.0,可以直接在函数调用中声明
out
变量,如下所示:

GetFileTimeSample.GetFileTimes(path, out DateTime fileDateCreated, out DateTime fileDateAccessed, out DateTime fileDateModified);
GetFileTimeSample

公共类GetFileTimeSample
{
专用consuint GENERIC_READ=0x8000000;
私有consuint FILE\u SHARE\u READ=0x1;
私有consuint FILE_ATTRIBUTE_NORMAL=0x80;
private const int无效的句柄值=-1;
私人建筑的开放性=3;
[StructLayout(LayoutKind.Sequential)]
私有结构文件时间
{
公共uint dwLowDateTime;
公共单位时间;
}
[DllImport(“kernel32.dll”,SetLastError=true)]
[返回:Marshallas(UnmanagedType.Bool)]
私有静态外部布尔闭合句柄(
IntPtr hObject
);
[DllImport(“kernel32.dll”,CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall,SetLastError=true)]
私有静态外部IntPtr创建文件(
字符串lpFileName,
uint DWD期望访问,
uint dwShareMode,
IntPtr安全属性,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr-hTemplateFile
);
[DllImport(“kernel32.dll”,SetLastError=true)]
私有静态外部bool GetFileTime(
IntPtr hFile,
ref FILETIME lpCreationTime,
ref FILETIME lpLastAccessTime,
ref FILETIME lpLastWriteTime
);
public static void GetFileTimes(字符串文件名、out DateTime CreationTime、out DateTime LastAccessTime、out DateTime LastWriteTime)
{
CreationTime=DateTime.MinValue;
LastAccessTime=DateTime.MinValue;
LastWriteTime=DateTime.MinValue;
IntPtr ptr=IntPtr.0;
FILETIME ftCreationTime=新建FILETIME();
FILETIME ftLastAccessTime=新FILETIME();
FILETIME ftLastWriteTime=新FILETIME();
尝试
{
ptr=CreateFile(文件名、通用读取、文件共享读取、IntPtr.Zero、打开现有、文件属性正常、IntPtr.Zero);
if(ptr.ToInt32()==无效的句柄值)
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
if(GetFileTime(ptr,ref-ftCreationTime,ref-ftLastAccessTime,ref-ftLastWriteTime)!=true)
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());

CreationTime=DateTime.FromFileTimeUtc(((长)ftCreationTime.dwHighDateTime)这里有一种通过命令行执行文件操作的方法。这不是最优雅的解决方案,但希望是一个有用的参考

using System;
using System.IO;
using System.Diagnostics;

namespace StackOverflow_FileNameShenanigans
{
    class Program
    {
        static void Main(string[] args)
        {
            string contents;

            DateTime origAccessDate;
            DateTime origCreateDate;
            long sizeBytes;

            string path = @"\\?\C:\Test\BadFileName.";

            try
            {
                contents = CommandLineFileOps.ReadAllText(path);
                origAccessDate = CommandLineFileOps.LastAccessTime(path);
                origCreateDate = CommandLineFileOps.CreationTime(path);
                sizeBytes = CommandLineFileOps.Length(path);

                Console.WriteLine($"Contents: {contents}");
                Console.WriteLine($"OrigAccessDate: {origAccessDate}");
                Console.WriteLine($"OrigCreateDate: {origCreateDate}");
                Console.WriteLine($"SizeBytes: {sizeBytes}");
                Console.ReadKey();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                Console.ReadKey();
            }
        }

    }

    public static class CommandLineFileOps
    {
        public static string ReadAllText(string path)
        {
            string contents;
            RunOnCommandLine($"type {path}", out contents);

            contents = contents.Substring(0, contents.Length - 3);
            return contents;
        }

        public static DateTime CreationTime(string path)
        {
            string output;
            RunOnCommandLine($"dir /T:C {path}", out output);

            string dateLine = output.Split('\n')[5];
            string dateStr = dateLine.Replace("                 ", "\n").Split('\n')[0];
            return DateTime.Parse(dateStr);
        }

        public static DateTime LastAccessTime(string path)
        {
            string output;
            RunOnCommandLine($"dir /T:A {path}", out output);

            string dateLine = output.Split('\n')[5];
            string dateStr = dateLine.Replace("                 ", "\n").Split('\n')[0];
            return DateTime.Parse(dateStr);
        }

        public static long Length(string path)
        {
            string output;
            RunOnCommandLine($"dir {path}", out output);

            string lengthLine = output.Split('\n')[6];
            string lengthStr = lengthLine.Replace("              ", "\n").Split('\n')[2].Split(' ')[0];
            return long.Parse(lengthStr);
        }

        private static int RunOnCommandLine(string line)
        {
            Process cmd = new Process();
            cmd.StartInfo.FileName = "cmd.exe";
            cmd.StartInfo.RedirectStandardInput = true;
            cmd.StartInfo.RedirectStandardOutput = true;
            cmd.StartInfo.CreateNoWindow = true;
            cmd.StartInfo.UseShellExecute = false;
            cmd.Start();

            cmd.StandardInput.WriteLine(line);
            cmd.StandardInput.Flush();
            cmd.StandardInput.Close();
            cmd.WaitForExit();

            int exitCode = cmd.ExitCode;
            return exitCode;
        }

        private static int RunOnCommandLine(string line, out string output)
        {
            string tempPath = Path.GetTempFileName();
            int exitCode = RunOnCommandLine($"{line} > {tempPath}");
            output = File.ReadAllText(tempPath);
            File.Delete(tempPath);

            return exitCode;
        }
    }
}
方法调用:

        string path = @"C:\Test\BadFileName.";

        DateTime createDate = cmdGetCreateDate(path);
        DateTime accessDate = cmdGetAccessDate(path);
        long bytes = cmdGetSizeBytes(path);
方法:

    private DateTime cmdGetCreateDate(string path)
    {
        DateTime createDate = new DateTime();
        int lastSlash = path.LastIndexOf(Convert.ToChar("\\"));
        string file = path.Substring(lastSlash + 1);
        string folder = path.Substring(0, lastSlash);

        string cmdexe = @"C:\Windows\System32\cmd.exe";
        string args = @"/c dir /T:C /A:-D """ + folder + "\"";

        Process procCreateDate = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = cmdexe,
                Arguments = args,
                UseShellExecute = false,
                RedirectStandardOutput = true,
                CreateNoWindow = true
            }
        };

        procCreateDate.Start();
        string output = procCreateDate.StandardOutput.ReadToEnd();

        if (!output.Contains(file))
        {
            return createDate; //File not found
        }

        string p = @"\b\d{2}/\d{2}/\d{4}\b\s+\d{2}:\d{2} ..";
        Regex rx = new Regex(p);
        Match m = rx.Match(output);

        if (m.Success)
        {
            DateTime.TryParse(m.Value, out createDate);
        }

        return createDate;
    }

private DateTime cmdGetAccessDate(string path)
    {
        DateTime accessDate = new DateTime();
        int lastSlash = path.LastIndexOf(Convert.ToChar("\\"));
        string file = path.Substring(lastSlash + 1);
        string folder = path.Substring(0, lastSlash);

        string cmdexe = @"C:\Windows\System32\cmd.exe";
        string args = @"/c dir /T:A /A:-D """ + folder + "\"";

        Process procCreateDate = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = cmdexe,
                Arguments = args,
                UseShellExecute = false,
                RedirectStandardOutput = true,
                CreateNoWindow = true
            }
        };

        procCreateDate.Start();
        string output = procCreateDate.StandardOutput.ReadToEnd();

        if (!output.Contains(file))
        {
            return accessDate; //File not found
        }

        string p = @"\b\d{2}/\d{2}/\d{4}\b\s+\d{2}:\d{2} ..";
        Regex rx = new Regex(p);
        Match m = rx.Match(output);

        if (m.Success)
        {
            DateTime.TryParse(m.Value, out accessDate);
        }

        return accessDate;
    }

    private long cmdGetSizeBytes(string path)
    {
        long bytes = -1;
        int lastSlash = path.LastIndexOf(Convert.ToChar("\\"));
        string file = path.Substring(lastSlash + 1);
        string folder = path.Substring(0, lastSlash);

        string cmdexe = @"C:\Windows\System32\cmd.exe";
        string args = @"/c dir /A:-D """ + folder + "\"";


        Process procCreateDate = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = cmdexe,
                Arguments = args,
                UseShellExecute = false,
                RedirectStandardOutput = true,
                CreateNoWindow = true
            }
        };

        procCreateDate.Start();
        string output = procCreateDate.StandardOutput.ReadToEnd();

        if (!output.Contains(file))
        {
            return bytes; //File not found
        }

        string p = @"\d+ " + file;
        Regex rx = new Regex(p);
        Match m = rx.Match(output);

        if (m.Success)
        {
            string[] splitVal = m.Value.Split(Convert.ToChar(" "));
            bytes = Convert.ToInt64(splitVal[0]);
        }

        return bytes;
    }

要复制:1)mkdir“C:\Test”2)echo“Test”>“\\?\C:\Test\BadFileName”。要清除:del“\\?\C:\Test\BadFileName。”这是一个很好的方法,我会研究一下。很好!我可以用你的方法得到文件的大小,但不确定如何获得日期信息。@complhex,这两种方法中的哪一种?如果你说的是
文件
类,有
文件.GetLastAccessTime
文件.GetLastWriteTime
。我在Ru上有错误非命令行调用($)。将它们切换到@并得到索引越界错误。您可能正在编译较低版本的.NET。“$”是一个插值运算符。它只允许您编写诸如:“Contents:+Contents as$”Contents:{Contents}之类的内容。此外,所有“@”does是指定您使用的是文字字符串。这对于必须转义许多字符的字符串非常有用,例如文件路径。由于您的帮助,我能够使用命令行解决此问题。我将在下面发布我的解决方案。我唯一做不到的事情是以二次精度捕获时间。远远不是事实上,在使用C#之类的编程语言时,这种方法显然是不可接受的。
        string path = @"C:\Test\BadFileName.";

        DateTime createDate = cmdGetCreateDate(path);
        DateTime accessDate = cmdGetAccessDate(path);
        long bytes = cmdGetSizeBytes(path);
    private DateTime cmdGetCreateDate(string path)
    {
        DateTime createDate = new DateTime();
        int lastSlash = path.LastIndexOf(Convert.ToChar("\\"));
        string file = path.Substring(lastSlash + 1);
        string folder = path.Substring(0, lastSlash);

        string cmdexe = @"C:\Windows\System32\cmd.exe";
        string args = @"/c dir /T:C /A:-D """ + folder + "\"";

        Process procCreateDate = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = cmdexe,
                Arguments = args,
                UseShellExecute = false,
                RedirectStandardOutput = true,
                CreateNoWindow = true
            }
        };

        procCreateDate.Start();
        string output = procCreateDate.StandardOutput.ReadToEnd();

        if (!output.Contains(file))
        {
            return createDate; //File not found
        }

        string p = @"\b\d{2}/\d{2}/\d{4}\b\s+\d{2}:\d{2} ..";
        Regex rx = new Regex(p);
        Match m = rx.Match(output);

        if (m.Success)
        {
            DateTime.TryParse(m.Value, out createDate);
        }

        return createDate;
    }

private DateTime cmdGetAccessDate(string path)
    {
        DateTime accessDate = new DateTime();
        int lastSlash = path.LastIndexOf(Convert.ToChar("\\"));
        string file = path.Substring(lastSlash + 1);
        string folder = path.Substring(0, lastSlash);

        string cmdexe = @"C:\Windows\System32\cmd.exe";
        string args = @"/c dir /T:A /A:-D """ + folder + "\"";

        Process procCreateDate = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = cmdexe,
                Arguments = args,
                UseShellExecute = false,
                RedirectStandardOutput = true,
                CreateNoWindow = true
            }
        };

        procCreateDate.Start();
        string output = procCreateDate.StandardOutput.ReadToEnd();

        if (!output.Contains(file))
        {
            return accessDate; //File not found
        }

        string p = @"\b\d{2}/\d{2}/\d{4}\b\s+\d{2}:\d{2} ..";
        Regex rx = new Regex(p);
        Match m = rx.Match(output);

        if (m.Success)
        {
            DateTime.TryParse(m.Value, out accessDate);
        }

        return accessDate;
    }

    private long cmdGetSizeBytes(string path)
    {
        long bytes = -1;
        int lastSlash = path.LastIndexOf(Convert.ToChar("\\"));
        string file = path.Substring(lastSlash + 1);
        string folder = path.Substring(0, lastSlash);

        string cmdexe = @"C:\Windows\System32\cmd.exe";
        string args = @"/c dir /A:-D """ + folder + "\"";


        Process procCreateDate = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = cmdexe,
                Arguments = args,
                UseShellExecute = false,
                RedirectStandardOutput = true,
                CreateNoWindow = true
            }
        };

        procCreateDate.Start();
        string output = procCreateDate.StandardOutput.ReadToEnd();

        if (!output.Contains(file))
        {
            return bytes; //File not found
        }

        string p = @"\d+ " + file;
        Regex rx = new Regex(p);
        Match m = rx.Match(output);

        if (m.Success)
        {
            string[] splitVal = m.Value.Split(Convert.ToChar(" "));
            bytes = Convert.ToInt64(splitVal[0]);
        }

        return bytes;
    }