Подтвердить что ты не робот

Лучший способ определить, есть ли ссылка на два пути к одному файлу в Windows?

Как мне сравнить 2 строки, чтобы определить, ссылаются ли они на один и тот же путь в Win32 с помощью C/С++?

В то время как это будет обрабатывать множество случаев, оно пропускает некоторые вещи:

_tcsicmp(szPath1, szPath2) == 0

Например:

  • косые черты/обратные косые черты

  • относительные/абсолютные пути.

[Изменить] Название изменено в соответствии с существующим вопросом С#.

4b9b3361

Ответ 2

используйте GetFullPathName из kernel32.dll, это даст вам абсолютный путь к файлу. Затем сравните его с другим путем, который вы используете с помощью простого сравнения строк.

edit: code

TCHAR buffer1[1000];
TCHAR buffer2[1000];
TCHAR buffer3[1000];
TCHAR buffer4[1000];

GetFullPathName(TEXT("C:\\Temp\\..\\autoexec.bat"),1000,buffer1,NULL);
GetFullPathName(TEXT("C:\\autoexec.bat"),1000,buffer2,NULL);
GetFullPathName(TEXT("\\autoexec.bat"),1000,buffer3,NULL);
GetFullPathName(TEXT("C:/autoexec.bat"),1000,buffer4,NULL);
_tprintf(TEXT("Path1: %s\n"), buffer1);
_tprintf(TEXT("Path2: %s\n"), buffer2);
_tprintf(TEXT("Path3: %s\n"), buffer3);
_tprintf(TEXT("Path4: %s\n"), buffer4);

приведенный выше код будет печатать один и тот же путь для всех трех представлений пути. После этого вы можете сделать поиск без учета регистра

Ответ 4

Простое сравнение строк недостаточно для сравнения путей для равенства. В окнах вполне возможно c:\foo\bar.txt и c:\temp\bar.txt указать точно такой же файл через символические и жесткие ссылки в файловой системе.

Сравнение путей, по сути, существенно заставляет вас открывать оба файла и сравнивать информацию о нижнем уровне. Любой другой метод будет иметь шелушащиеся результаты.

Посмотрите на эту отличную статью, которую сделал Люциан по этому вопросу. Код находится в VB, но он довольно переводится на C/С++, поскольку он PInvoke'd использует большинство методов.

http://blogs.msdn.com/vbteam/archive/2008/09/22/to-compare-two-filenames-lucian-wischik.aspx

Ответ 5

Если у вас есть доступ к библиотекам Boost, попробуйте

bool boost::filesystem::path::equivalent( const path& p1, const path& p2 )

http://www.boost.org/doc/libs/1_53_0/libs/filesystem/doc/reference.html#equivalent

Подводя итог из документов: Возвращает true, если заданные объекты path разрешены для одного и того же объекта файловой системы, else false.

Ответ 6

Основываясь на ответах GetFileInformationByHandle(), вот код.

Примечание. Это будет работать, только если файл уже существует...

//Determine if 2 paths point ot the same file...
//Note: This only works if the file exists
static bool IsSameFile(LPCWSTR szPath1, LPCWSTR szPath2)
{
    //Validate the input
    _ASSERT(szPath1 != NULL);
    _ASSERT(szPath2 != NULL);

    //Get file handles
    HANDLE handle1 = ::CreateFileW(szPath1, 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 
    HANDLE handle2 = ::CreateFileW(szPath2, 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 

    bool bResult = false;

    //if we could open both paths...
    if (handle1 != INVALID_HANDLE_VALUE && handle2 != INVALID_HANDLE_VALUE)
    {
        BY_HANDLE_FILE_INFORMATION fileInfo1;
        BY_HANDLE_FILE_INFORMATION fileInfo2;
        if (::GetFileInformationByHandle(handle1, &fileInfo1) && ::GetFileInformationByHandle(handle2, &fileInfo2))
        {
            //the paths are the same if they refer to the same file (fileindex) on the same volume (volume serial number)
            bResult = fileInfo1.dwVolumeSerialNumber == fileInfo2.dwVolumeSerialNumber &&
                      fileInfo1.nFileIndexHigh == fileInfo2.nFileIndexHigh &&
                      fileInfo1.nFileIndexLow == fileInfo2.nFileIndexLow;
        }
    }

    //free the handles
    if (handle1 != INVALID_HANDLE_VALUE )
    {
        ::CloseHandle(handle1);
    }

    if (handle2 != INVALID_HANDLE_VALUE )
    {
        ::CloseHandle(handle2);
    }

    //return the result
    return bResult;
}

Ответ 7

Что вам нужно сделать, так это получить канонический путь.

Для каждого пути вы попросите файловую систему преобразовать в канонический путь или предоставить вам идентификатор, который однозначно идентифицирует файл (например, iNode).

Затем сравните канонический путь или уникальный идентификатор.

Примечание: Не пытайтесь выяснить, как коническая дорожка сама файловая система может делать что-то с символическими ссылками и т.д., Которые нелегко обрабатываются, если вы не знакомы с файловой системой.

Ответ 8

Сравнение фактических строк пути не даст точных результатов, если вы ссылаетесь на UNC или канонические пути (то есть на все, кроме локального пути).

shlwapi.h имеет несколько Функции пути, которые могут вам пригодиться в определении того, являются ли ваши пути одинаковыми.

Он содержит функции, такие как PathIsRoot, которые могут использоваться в функции большей области.

Ответ 9

Откройте оба файла и используйте GetFinalPathNameByHandle() против HANDLE s. Затем сравните пути.

Ответ 10

Если файлы существуют, и вы можете иметь дело с потенциальным состоянием гонки, и производительность удалась от открытия файлов, то несовершенное решение, которое должно работать на любой платформе, - это открыть один файл для записи самостоятельно, закрыть его, а затем открыть для записи снова после открытия другого файла для записи. Поскольку доступ на запись разрешен только для исключительных ситуаций, если вы могли открыть первый файл для записи в первый раз, но не во второй раз, скорее всего, вы заблокировали свой собственный запрос при попытке открыть оба файла.

(возможно, конечно, также, что в какой-то другой части системы открыт один из ваших файлов)