How to create folder with trailing dot (.) in .NET/C#?

不打扰是莪最后的温柔 提交于 2019-12-06 13:43:28
Keith Nicholas

Try:

using System.Runtime.InteropServices;
class Program
{
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool CreateDirectory(string lpPathName, IntPtr lpSecurityAttributes);

    private static void Main(string[] args)
    {
        CreateDirectory(@"\\?\c:\temp\MyCorp Inc.", IntPtr.Zero);
    }

And refer to You cannot delete a file or a folder on an NTFS file system volume.

Microsoft clearly states that this is something that should not be done: http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx

Do not end a file or directory name with a space or a period. Although the underlying file system may support such names, the Windows shell and user interface does not. However, it is acceptable to specify a period as the first character of a name. For example, ".temp".

Mitch

That is not a limitation of .NET, but of the Win32 API. Try to create one in a command shell:

c:\drop>mkdir test.

c:\drop>dir
 Volume in drive C has no label.
 Volume Serial Number is C0F3-338B

 Directory of c:\drop

2013-04-02  17:54    <DIR>          .
2013-04-02  17:54    <DIR>          ..
2013-04-02  17:54    <DIR>          test

See MSDN for naming reccomendations. To quote:

•Do not end a file or directory name with a space or a period. Although the underlying file system may support such names, the Windows shell and user interface does not. However, it is acceptable to specify a period as the first character of a name. For example, ".temp".

If you are really quite insistent on using a trailing dot, use \\?\C:\path..

c:\drop>mkdir \\?\c:\drop\test2.

c:\drop>dir
 Volume in drive C has no label.
 Volume Serial Number is C0F3-338B

 Directory of c:\drop

2013-04-02  17:58    <DIR>          .
2013-04-02  17:58    <DIR>          ..
2013-04-02  17:54    <DIR>          test
2013-04-02  17:58    <DIR>          test2.

Edit: The requirement as listed in the contents is that no additional files are created, so don't use a file. You can create a "name" stream on the directory and store data there. See the following for an example:

c:\drop>mkdir "Example Company Name"
c:\drop>notepad "Example Company Name:name.txt"
c:\drop>dir
 Volume in drive C has no label.
 Volume Serial Number is C0F3-338B

 Directory of c:\drop

2013-04-02  18:25    <DIR>          .
2013-04-02  18:25    <DIR>          ..
2013-04-02  18:25    <DIR>          Example Company Name
               0 File(s)              0 bytes
               3 Dir(s)  77,336,379,392 bytes free
c:\drop>dir "Example Company Name"
 Volume in drive C has no label.
 Volume Serial Number is C0F3-338B

 Directory of c:\drop\Example Company Name

2013-04-02  18:25    <DIR>          .
2013-04-02  18:25    <DIR>          ..
               0 File(s)              0 bytes
               2 Dir(s)  77,336,313,856 bytes free

Or in .NET:

class Program
{
    static void Main(string[] args)
    {
        string companyName = "Example Company?*, Inc.";

        //Example Company Inc
        var sanitizedName = sanitize(companyName);

        //Create the directory
        Directory.CreateDirectory(sanitizedName);

        //Create the name store
        var nameStreamPath = sanitizedName + ":Name";
        writeFileContent(companyName, nameStreamPath);

        //Try to return the name
        Console.WriteLine(getFileContent(nameStreamPath));
        Console.ReadLine();
    }

    private static string getFileContent(string path)
    {
        using (var sr = new StreamReader(new FileStream(
            // we have to call CreateFile directly to avoid overzealous path validation
            NativeMethods.CreateFileOrFail(path, false), FileAccess.Read)))
        {
            return sr.ReadToEnd();
        }
    }

    private static void writeFileContent(string companyName, string path)
    {
        using (var sw = new StreamWriter(new FileStream(
            // We have to call CreateFile directly to avoid overzealous path validation
            NativeMethods.CreateFileOrFail(path, true), FileAccess.Write)))
        {
            sw.Write(companyName);
        }
    }

    private static string sanitize(string path)
    {
        char[] newPath = new char[path.Length];
        int newPathLoc = 0;
        for (int i = 0; i < path.Length; i++)
        {
            if (char.IsLetter(path[i]) || char.IsDigit(path[i]))
            {
                newPath[newPathLoc] = path[i];
                newPathLoc++;
            }
        }
        return new string(newPath, 0, newPathLoc);
    }
}

class NativeMethods
{
    [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    private static extern SafeFileHandle CreateFile(
        string fileName,
        [MarshalAs(UnmanagedType.U4)] FileAccess fileAccess,
        [MarshalAs(UnmanagedType.U4)] FileShare fileShare,
        IntPtr securityAttributes,
        [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
        [MarshalAs(UnmanagedType.U4)] FileAttributes flags,
        IntPtr template);

    public static SafeFileHandle CreateFileOrFail(string path, bool write)
    {
        var handle = CreateFile(path,
            write ? FileAccess.Write : FileAccess.Read,
            write ? FileShare.None : FileShare.Read,
            IntPtr.Zero,
            write ? FileMode.Create : FileMode.Open,
            FileAttributes.Normal,
            IntPtr.Zero);

        if (handle.IsInvalid)
            throw new System.ComponentModel.Win32Exception();

        return handle;
    }
}
7-isnotbad

Updated:

I have noticed two things!

1) Your requirement:

I have many customers that name their folders according to company name, for example "Some Corp Ltd.", these names often contain trailing dots. I can not store names anywhere else, I do not have database and I can not create extra files, this is the requirement.

2) You haven't got an answer

My suggestion is to add an extra character at the end of directory name, which will be hidden to normal view, but still exist! Which makes us happy!

Try this

You have to append a special character at the end of the directory name

System.IO.Directory.CreateDirectory
                    (@"D:\Sync.inc." + (char)(128));

Note:(char)(128) to (char)(158) may help

Try a blast!

for (int i = 128; i <= 158; i++)
{
    System.IO.Directory.CreateDirectory
        (@"D:\Sync.inc." + (char)(i));
}

Anyway as from MS:

If the dot is at the end of the name, Windows will ignore the dot(s) by default.

Have a look at http://social.technet.microsoft.com/Forums/en-US/w7itproui/thread/84978c71-8203-404b-94cf-b05b14be99db/

If you attempt to do this manually in Windows Explorer even Explorer does not allow the trailing dot and removes it for you.

I imagine this is a limitation of Windows itself owing to a period at the end usually signifying a file extension.

At this time I would say it is not possible.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!