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

推荐订阅源

OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Latest news
Latest news
J
Java Code Geeks
The Register - Security
The Register - Security
V
Visual Studio Blog
IT之家
IT之家
Martin Fowler
Martin Fowler
The GitHub Blog
The GitHub Blog
B
Blog RSS Feed
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Stack Overflow Blog
Stack Overflow Blog
The Cloudflare Blog
N
Netflix TechBlog - Medium
博客园 - 聂微东
D
Docker
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园_首页
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
C
Check Point Blog
美团技术团队
爱范儿
爱范儿
A
About on SuperTechFans
Y
Y Combinator Blog
Engineering at Meta
Engineering at Meta
PCI Perspectives
PCI Perspectives
MyScale Blog
MyScale Blog
T
Threatpost
S
Securelist
量子位
C
Cyber Attacks, Cyber Crime and Cyber Security
Vercel News
Vercel News
宝玉的分享
宝玉的分享
Project Zero
Project Zero
S
Security @ Cisco Blogs
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Cisco Talos Blog
Cisco Talos Blog
罗磊的独立博客
M
MIT News - Artificial intelligence
雷峰网
雷峰网
G
Google Developers Blog
T
The Blog of Author Tim Ferriss
Google Online Security Blog
Google Online Security Blog
The Last Watchdog
The Last Watchdog
P
Proofpoint News Feed
Security Archives - TechRepublic
Security Archives - TechRepublic
Schneier on Security
Schneier on Security
H
Hacker News: Front Page
T
Troy Hunt's Blog
U
Unit 42
Scott Helme
Scott Helme

博客园 - 光阴四溅

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;

}