惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Azure Blog
Microsoft Azure Blog
H
Hacker News: Front Page
A
About on SuperTechFans
云风的 BLOG
云风的 BLOG
aimingoo的专栏
aimingoo的专栏
Martin Fowler
Martin Fowler
博客园 - 叶小钗
Last Week in AI
Last Week in AI
Recent Announcements
Recent Announcements
P
Palo Alto Networks Blog
Webroot Blog
Webroot Blog
Hacker News: Ask HN
Hacker News: Ask HN
IT之家
IT之家
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Threat Research - Cisco Blogs
C
CERT Recently Published Vulnerability Notes
Google DeepMind News
Google DeepMind News
Hugging Face - Blog
Hugging Face - Blog
H
Help Net Security
P
Privacy & Cybersecurity Law Blog
C
Cisco Blogs
罗磊的独立博客
The GitHub Blog
The GitHub Blog
M
MIT News - Artificial intelligence
人人都是产品经理
人人都是产品经理
The Cloudflare Blog
Y
Y Combinator Blog
AWS News Blog
AWS News Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
K
Kaspersky official blog
博客园 - 司徒正美
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Security Archives - TechRepublic
Security Archives - TechRepublic
The Last Watchdog
The Last Watchdog
Jina AI
Jina AI
MyScale Blog
MyScale Blog
TaoSecurity Blog
TaoSecurity Blog
大猫的无限游戏
大猫的无限游戏
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Cisco Talos Blog
Cisco Talos Blog
美团技术团队
T
Tor Project blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
博客园 - 【当耐特】
博客园 - 聂微东
V2EX - 技术
V2EX - 技术
I
Intezer
V
Visual Studio Blog
酷 壳 – CoolShell
酷 壳 – CoolShell

博客园 - 光阴四溅

The request was aborted: Could not create SSL/TLS secure channel. Gets 403 when calling WCF Service in intranet RESTful WCF returns 400 Bad Request and more 用WIX做MSI包 再见美罗 溜冰 Use ILDASM.exe as an external tool in your VS2008 - 光阴四溅 一个英语在线小词典 -- 使用WPF开发 Long Paths in .NET, Part 1 of 3 [Kim Hamilton][译] Have a break... You call it love 上火了 上火了 一个VARCHAR和一个NVARCHAR相加 "Atlas" July Community Technology Preview Released -- 安装时出现String cannot have zero length错误 DTS--在变量或是在临时表和表变量中使用Input Global Variables ms真是越来越搞了 当在一个xml doc里面使用一个很大xml doc作为attribute时sp_xml_preparedocument返回Unspecified error 莲花 半夜里在网络上游荡
Long Paths in .NET, Part 2 of 3 [Kim Hamilton][译]
光阴四溅 · 2007-04-26 · via 博客园 - 光阴四溅

就目前来说, 我们建议那些碰到MAX_PATH问题的客户重新安排他们的目录从而使文件路径变的短一些. 这看起来像是个不负责任的逃跑吧? 不过对于用户来说却是最简单的, 原因有二: 1, 不需要额外的工具来访问文件(Explorer不能打开long path的文件, 你必须自己写一个!) 2, 能够充分使用System.IO提供的功能而不需要自己再写n多的重复代码. 然而, 如果你真的需要使用超过MAX_PATHlong path的话, 我会给你展示一些demo.

上次我们已经说到可以在Unicode版本的Win32 API中使用”\\?\”前缀就可以处理最大32k的路径了. 下面这些代码展示使用这种方法来做一些常规的文件操作.

删除一个文件

我们还是从最简单的开始吧 删除一个文件. 不要忘记Explorer不能替你删除那些long path的文件, 那你就不得不自己擦屁股了.

首先, 我们要确认一下Win32 API中的DeleteFile是不是支持long path. 从下面这段来看答案是肯定的:

In the ANSI version of this function, the name is limited to MAX_PATH characters. To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\\?\" to the path. For more information, see Naming a File.


那么我们先添加
PInvoke signature:

using System;

using System.Runtime.InteropServices;

[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]

[return: MarshalAs(UnmanagedType.Bool)]

internal static extern bool DeleteFile(string lpFileName);


然后我们所要做的就是在文件名前面\\?\:

// This code snippet is provided under the Microsoft Permissive License.

public static void Delete(string fileName) {

    string formattedName = @"\\?\" + fileName;

    DeleteFile(formattedName);

}

           
对于一些简单的文件操作, 比如删除, 移动和重命名,像上面这样直接API就搞定了. 另外有些复杂的情况, 比如写一个文件, 你可以混合调用Win32 APISystem.IO.

写入和读取一个文件

首先你要调用Win32 CreateFile方法来创建或打开一个文件. CreateFile会返回一个文件句柄, 你可以把它传给System.IO.FileStream的构造函数. 剩下的就由FileStream搞定了.

// This code snippet is provided under the Microsoft Permissive License.

using System;

using System.IO;

using System.Runtime.InteropServices;

using Microsoft.Win32.SafeHandles;

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]

internal static extern SafeFileHandle CreateFile(

    string lpFileName,

    EFileAccess dwDesiredAccess,

    EFileShare dwShareMode,

    IntPtr lpSecurityAttributes,

    ECreationDisposition dwCreationDisposition,

    EFileAttributes dwFlagsAndAttributes,

    IntPtr hTemplateFile);

public static void TestCreateAndWrite(string fileName) {

    string formattedName = @"\\?\" + fileName;

    // Create a file with generic write access

    SafeFileHandle fileHandle = CreateFile(formattedName,

        EFileAccess.GenericWrite, EFileShare.None, IntPtr.Zero,

        ECreationDisposition.CreateAlways, 0, IntPtr.Zero);

    // Check for errors

    int lastWin32Error = Marshal.GetLastWin32Error();

    if (fileHandle.IsInvalid) {

        throw new System.ComponentModel.Win32Exception(lastWin32Error);

    }

    // Pass the file handle to FileStream. FileStream will close the

    // handle

    using (FileStream fs = new FileStream(fileHandle,

                                    FileAccess.Write)) {

        fs.WriteByte(80);

        fs.WriteByte(81);

        fs.WriteByte(83);

        fs.WriteByte(84);

    }

}


在这个例子里我们往文件里面写了一些数据. 但是一旦你构造了FileStream, 你就可以像往常一样使用它了. 比如把它包进一个BinaryWriter等等.

如果你只是想打开而不是新建一个文件, 那么就把参数dwCreationDispositionCreateAlways改成OpenExisting. 如果你想读取而不是写入一个文件, 那么就把参数dwDesiredAccessGenericWrite改成GenericRead.

本文结束的部分有这么枚举的定义.

查找文件和目录

到目前为止我们方案看起来不错. 但是设想一下你要找到某个特定文件夹下面的子文件夹和文件...ah...看起来我们像是在重写.NET类库. J            

// This code snippet is provided under the Microsoft Permissive License.

using System;

using System.Collections.Generic;

using System.IO;

using System.Runtime.InteropServices;

using Microsoft.Win32.SafeHandles;

[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]

internal static extern IntPtr FindFirstFile(string lpFileName, out

                                WIN32_FIND_DATA lpFindFileData);

[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]

internal static extern bool FindNextFile(IntPtr hFindFile, out

                                WIN32_FIND_DATA lpFindFileData);

[DllImport("kernel32.dll", SetLastError = true)]

[return: MarshalAs(UnmanagedType.Bool)]

internal static extern bool FindClose(IntPtr hFindFile);

// Assume dirName passed in is already prefixed with \\?\

public static List<string> FindFilesAndDirs(string dirName) {

    List<string> results = new List<string>();

    WIN32_FIND_DATA findData;

    IntPtr findHandle = FindFirstFile(dirName + @"\*", out findData);

    if (findHandle != INVALID_HANDLE_VALUE) {

        bool found;

        do {

            string currentFileName = findData.cFileName;

            // if this is a directory, find its contents

            if (((int)findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {

                if (currentFileName != "." && currentFileName != "..")

                {

                List<string> childResults = FindFilesAndDirs(Path.Combine(dirName, currentFileName));

                // add children and self to results

                results.AddRange(childResults);

                results.Add(Path.Combine(dirName, currentFileName));

                }

            }

            // it's a file; add it to the results

            else {

                results.Add(Path.Combine(dirName, currentFileName));

            }

            // find next

            found = FindNextFile(findHandle, out findData);

        }

        while (found);

    }

    // close the find handle

    FindClose(findHandle);

    return results;

}

相关资源:

Constants, StructsEnums:

internal static IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);

internal static int FILE_ATTRIBUTE_DIRECTORY = 0x00000010;

internal const int MAX_PATH = 260;

[StructLayout(LayoutKind.Sequential)]

internal struct FILETIME {

    internal uint dwLowDateTime;

    internal uint dwHighDateTime;

};

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]

internal struct WIN32_FIND_DATA {

    internal FileAttributes dwFileAttributes;

    internal FILETIME ftCreationTime;

    internal FILETIME ftLastAccessTime;

    internal FILETIME ftLastWriteTime;

    internal int nFileSizeHigh;

    internal int nFileSizeLow;

    internal int dwReserved0;

    internal int dwReserved1;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]

    internal string cFileName;

    // not using this

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]

    internal string cAlternate;

}

[Flags]

public enum EFileAccess : uint {

    GenericRead = 0x80000000,

    GenericWrite = 0x40000000,

    GenericExecute = 0x20000000,

    GenericAll = 0x10000000,

}

[Flags]

public enum EFileShare : uint {

    None = 0x00000000,

    Read = 0x00000001,

    Write = 0x00000002,

    Delete = 0x00000004,

}

public enum ECreationDisposition : uint {

    New = 1,

    CreateAlways = 2,

    OpenExisting = 3,

    OpenAlways = 4,

    TruncateExisting = 5,

}

[Flags]

public enum EFileAttributes : uint {

    Readonly = 0x00000001,

    Hidden = 0x00000002,

    System = 0x00000004,

    Directory = 0x00000010,

    Archive = 0x00000020,

    Device = 0x00000040,

    Normal = 0x00000080,

    Temporary = 0x00000100,

    SparseFile = 0x00000200,

    ReparsePoint = 0x00000400,

    Compressed = 0x00000800,

    Offline = 0x00001000,

    NotContentIndexed = 0x00002000,

    Encrypted = 0x00004000,

    Write_Through = 0x80000000,

    Overlapped = 0x40000000,

    NoBuffering = 0x20000000,

    RandomAccess = 0x10000000,

    SequentialScan = 0x08000000,

    DeleteOnClose = 0x04000000,

    BackupSemantics = 0x02000000,

    PosixSemantics = 0x01000000,

    OpenReparsePoint = 0x00200000,

    OpenNoRecall = 0x00100000,

    FirstPipeInstance = 0x00080000

}

[StructLayout(LayoutKind.Sequential)]

public struct SECURITY_ATTRIBUTES {

    public int nLength;

    public IntPtr lpSecurityDescriptor;

    public int bInheritHandle;

}