Как я могу определить, что несколько форматов пути к файлу указывают на одно и то же физическое местоположение
Возможный дубликат:
Лучший способ определить, является ли ссылка двух ссылок на один и тот же файл на С#
Существует несколько способов указать расположение каталога.
Например:
\\имя_компьютера\с $\ ROOTPATH \ Subpath
\\имя_компьютера\shareName (общий доступ к subPath)
C:\ROOTPATH \ Subpath
subPath (относительный путь, если он уже находится в C:\rootPath
Мне нужно определить, что все эти пути "равны" друг другу (на самом деле это то же физическое местоположение на жестком диске).
Есть ли способ сделать это на С#?
Ответы
Ответ 1
В качестве Oded состояний это сложно сделать в .Net. Вы можете обмануть (в зависимости от ваших точных требований и разрешений и т.д.), Написав файл с длинным произвольно сгенерированным именем файла в этом месте, а затем посмотрев, сможете ли вы увидеть его из другого места. Я считаю, что это довольно звуковой тест, а не полагаться на разрешение подключенных дисков и т.д.
Хорошо, много извинений для VB - все, что у меня есть на этом крошечном нетбуке... С# не будет слишком отличаться...
использование, например
If sameLocation("\\machineName\c$\rootPath\subPath","\\machineName\shareName") Then...
Public Function sameLocation(ByVal sPath1 As String, ByVal sPath2 As String) As TriState
Dim sFile As String = randomFilename()
Dim sFullPath1 As String = sPath1 & "\" & sFile
Dim sFullPath2 As String = sPath2 & "\" & sFile
Dim bReturn As Boolean = False
Try
Dim fs As New FileStream(sFullPath1, FileMode.CreateNew)
fs.Close()
Catch ex As Exception
Return TriState.UseDefault
End Try
Try
bReturn = File.Exists(sFullPath2)
Catch ex As Exception
Return TriState.UseDefault
End Try
File.Delete(sFullPath1)
Return bReturn
End Function
Public Function randomFilename() As String
Dim r As New Random
Randomize(My.Computer.Clock.TickCount)
Dim sb As New StringBuilder
Dim chars As Int16 = 100
While chars > 0
chars -= 1
sb.Append(Chr(r.Next(26) + 65))
End While
Return sb.ToString
End Function
Вы можете добавить дополнительную безопасность, то есть прочитать метку времени и т.д.
Ответ 2
Вам нужно использовать GetFileInformationByHandle.
Просмотрите ответ в файле StackOverflow и MSDN.
Вот метод, который я написал, который работает с каталогами:
using System;
using System.Runtime.InteropServices;
namespace CompareByPath
{
public static class DirectoryHelper
{
// all user defined types copied from
// http://pinvoke.net/default.aspx/kernel32.CreateFile
// http://pinvoke.net/default.aspx/kernel32.GetFileInformationByHandle
// http://pinvoke.net/default.aspx/kernel32.CloseHandle
public const short INVALID_HANDLE_VALUE = -1;
struct BY_HANDLE_FILE_INFORMATION
{
public uint FileAttributes;
public System.Runtime.InteropServices.ComTypes.FILETIME CreationTime;
public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime;
public System.Runtime.InteropServices.ComTypes.FILETIME LastWriteTime;
public uint VolumeSerialNumber;
public uint FileSizeHigh;
public uint FileSizeLow;
public uint NumberOfLinks;
public uint FileIndexHigh;
public uint FileIndexLow;
}
[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
}
[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
}
public enum ECreationDisposition : uint
{
New = 1,
CreateAlways = 2,
OpenExisting = 3,
OpenAlways = 4,
TruncateExisting = 5
}
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GetFileInformationByHandle(IntPtr hFile, out BY_HANDLE_FILE_INFORMATION lpFileInformation);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
static extern IntPtr CreateFile(String lpFileName, UInt32 dwDesiredAccess, UInt32 dwShareMode, IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition, UInt32 dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);
public static bool CompareDirectories(string d1, string d2)
{
bool result = false;
BY_HANDLE_FILE_INFORMATION info1;
BY_HANDLE_FILE_INFORMATION info2;
IntPtr fileHandle1 = CreateFile(d1, (uint)EFileAccess.GenericRead, (uint)EFileShare.Read, IntPtr.Zero, (uint)ECreationDisposition.OpenExisting, (uint)(EFileAttributes.Directory | EFileAttributes.BackupSemantics), IntPtr.Zero);
if (fileHandle1.ToInt32() != INVALID_HANDLE_VALUE)
{
bool rc = GetFileInformationByHandle(fileHandle1, out info1);
if ( rc )
{
IntPtr fileHandle2 = CreateFile(d2, (uint)EFileAccess.GenericRead, (uint)EFileShare.Read, IntPtr.Zero, (uint)ECreationDisposition.OpenExisting, (uint)(EFileAttributes.Directory | EFileAttributes.BackupSemantics), IntPtr.Zero);
if (fileHandle2.ToInt32() != INVALID_HANDLE_VALUE)
{
rc = GetFileInformationByHandle(fileHandle2, out info2);
if ( rc )
{
if (( info1.FileIndexHigh == info2.FileIndexHigh) &&
( info1.FileIndexLow == info2.FileIndexLow) &&
( info1.VolumeSerialNumber == info2.VolumeSerialNumber))
{
result = true;
}
}
}
CloseHandle(fileHandle2);
}
}
CloseHandle(fileHandle1);
return result;
}
}
}
Ответ 3
В Windows существует много схем псевдонимов:
- короткие и длинные имена
- символические ссылки и жесткие ссылки
- Имена UNC и сопоставленные диски
- несколько подключенных дисков к одному и тому же сетевому пути
- d:\folder\paths против \?\d\folder\paths
- Точки монтирования NTFS
И любой из них может отображаться на любом уровне в дереве каталогов. В .NET вы можете разрешить некоторые из них, но не другие.
Как хакерский подход, попробуйте блокировку/разблокировку. Заблокируйте файл как имя 1, попробуйте открыть его как имя 2, убедитесь, что он сработал. Затем разблокируйте, попробуйте снова открыть, убедитесь, что он преуспел. И так далее, несколько раз, чтобы избежать ложных срабатываний. В отличие от способа El Ronnoco, этот детектирует как псевдонимы уровня, так и уровня файла.
В некоторых сетевых файловых системах блокировка может вообще не поддерживаться. Кроме того, это может занять некоторое время - каждая операция блокировки/разблокировки/открытия является обходной сетью.
Но это действительно зависит от ваших требований. Если короткие/длинные имена - это все, с чем вам приходится иметь дело, это перебор.
EDIT: дополнительные осложнения, если файл доступен только для чтения или уже открыт кем-то другим.
Ответ 4
В .NET нет собственного способа сделать это - это слишком низкий уровень.
Вы можете использовать API окон для этого (глядя на индексный каталог каталога или какой-либо другой идентификатор), но я не знаю, какой API будет раскрывать это.
Ответ 5
AKAIK вы даже можете сопоставить один и тот же диск со многими буквами дисков или подкаталогами. Также можно разделить сетевые общие каталоги, и вы никогда не знаете, являются ли они одинаковыми или нет.
Возможно, вы могли бы добавить информацию, почему вам нужно это знать.
Ответ 6
Хороший вопрос, может быть, не будет изящного ответа.
Лучшее, что я могу найти, чтобы указать вам на ваш путь, - это оператор командной строки net share
. Если вы можете программно отображать и перерабатывать текст, созданный этой командой, вы можете сопоставить сетевые ресурсы 1:1 с их локальными папками назначения. Затем вы можете искать экземпляры этих общих карт в заданном пути и заменять их эквивалентами локальной папки перед выполнением базового сравнения строк.