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

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - 光阴四溅

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;

}