Как проверить, открыт ли файл другим процессом в C? - PullRequest
9 голосов
/ 23 декабря 2009

Я вижу, что стандарт C не может определить, открыт ли файл в другом процессе. Поэтому ответ должен содержать несколько примеров для каждой платформы. Мне нужна эта проверка для Visual C ++ / Windows, хотя.

Ответы [ 8 ]

8 голосов
/ 10 октября 2012

windows: попробуйте открыть файл в монопольном режиме. Если это работает, никто больше не открыл файл и не сможет открыть файл

HANDLE fh;
fh = CreateFile(filename, GENERIC_READ, 0 /* no sharing! exclusive */, NULL, OPEN_EXISTING, 0, NULL);
if ((fh != NULL) && (fh != INVALID_HANDLE_VALUE))
{
   // the only open file to filename should be fh.
   // do something
   CloseHande(fh);
}

MS говорит: dwShareMode

Режим совместного использования объекта, который может быть прочитан, записан, либо удален, либо удален, либо все из них, либо отсутствует (см. Следующую таблицу).

Если этот параметр равен нулю и CreateFile завершается успешно, объект не может быть общим и не может быть открыт снова, пока не будет закрыт дескриптор.

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

http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx

расширение: Как удалить (не только для чтения) файловую файловую систему, которую никто не может открыть для чтения / записи?

право доступа FILE_READ_ATTRIBUTES, а не DELETE. DELETE может вызвать проблемы с общим ресурсом smb (для серверов MS Windows) - CreateFile останется с все еще открытым FileHandle / Device / Mup: xxx filename - почему и когда бы ни был этот Mup. Не произойдет с правом доступа FILE_READ_ATTRIBUTES используйте FILE_FLAG_OPEN_REPARSE_POINT, чтобы удалить имя файла. В противном случае вы удалите цель символической ссылки - что обычно не то, что вы хотите

HANDLE fh;
fh = CreateFile(filename,  FILE_READ_ATTRIBUTES, FILE_SHARE_DELETE /* no RW sharing! */, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_DELETE_ON_CLOSE, NULL);
if ((fh != NULL) && (fh != INVALID_HANDLE_VALUE))
{
    DeleteFile(filename); /* looks stupid?
                          * but FILE_FLAG_DELETE_ON_CLOSE will not work on some smb shares (e.g. samba)!
                          * FILE_SHARE_DELETE should allow this DeleteFile() and so the problem could be solved by additional DeleteFile()
                          */
    CloseHande(fh); /* a file, which no one has currently opened for RW is delete NOW */

} 

что делать с открытым файлом? Если файл открыт, и вам разрешено удалить ссылку, вы оставите файл, в котором последующие открытия приведут к ACCESS_DENIED. Если у вас есть временная папка, лучше переименовать ее (filename, tempdir / filename.delete) и удалить tempdir / filename.delete.

8 голосов
/ 23 декабря 2009

Невозможно сказать, если другой процесс явно не запрещает доступ к файлу. В MSVC вы бы сделали это с _fsopen(), указав _SH_DENYRD для аргумента shflag. Идея заинтересованности в том, открыт ли файл, который не заблокирован иным образом, глубоко ошибочна в многозадачной операционной системе. Он может открыться через микросекунду после того, как вы обнаружите, что это не так. Это также причина того, что в Windows нет функции IsFileLocked ().

Если вам нужен синхронизированный доступ к файлам, вам нужно добавить его с именованным мьютексом, используйте CreateMutex ().

4 голосов
/ 11 марта 2015

Для Windows этот код также работает:

boolean isClosed(File f) { return f.renameTo(f); }

Открытый файл не может быть переименован, и переименование с тем же именем не вызывает другую ошибку. Таким образом, если переименование завершилось успешно, не сделав что-то действительно, вы знаете, что файл не открыт.

3 голосов
/ 23 декабря 2009

Получение информации open_files - СЛОЖНО, это все равно что тянуть зубы, и если у вас нет срочной необходимости в этом, вам не следует просить «несколько примеров для каждой платформы» просто так. Просто мое мнение, конечно.

Linux и многие системы Unix имеют системную утилиту под названием lsof, которая находит дескрипторы открытых файлов и прочее. Это достигается путем доступа к /dev/kmem, который является псевдофайлом, содержащим копию «живой» памяти ядра, то есть рабочее хранилище ядра операционной системы. Естественно, там есть таблицы открытых файлов, а структура памяти с открытым исходным кодом и задокументирована, так что lsof просто нужно заняться этим, найти информацию и отформатировать ее для пользователя.

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

Все, что доступно, вероятно, используется утилитами Марка Руссиновича SysInternals; первым приходит на ум FileMon. Глядя на это может дать вам некоторые подсказки. Обновление: Мне только что сообщили, что SysInternals Handles.exe еще ближе к тому, что вы хотите.

Если вам удастся понять это, хорошо; в противном случае вас может заинтересовать отслеживание операций открытия / закрытия файлов по мере их появления: Windows API предлагает щедрую кучку так называемых хуков: http://msdn.microsoft.com/en-us/library/ms997537.aspx. хуки позволяют запрашивать уведомление при возникновении определенных событий в системе. Я считаю, что есть один, который скажет вам, когда программа & ndash; общесистемная & ndash; открывает файл Таким образом, вы можете создать свой собственный список файлов, открытых на время прослушивания ваших хуков. Я не знаю наверняка, но я подозреваю, что это может быть то, что делает FileMon.

Доступ к API Windows, включая функции перехвата, можно получить из C. Перехватчики всей системы потребуют от вас создания DLL для загрузки вместе с вашей программой.

Надеюсь, что эти советы помогут вам начать работу.

1 голос
/ 23 декабря 2009

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

0 голосов
/ 16 ноября 2018

Вы можете использовать что-то вроде этого. Это не правильное решение. Но это работает,

 bool IsFileDownloadComplete(const std::wstring& dir, const std::wstring& fileName) 
    {
        std::wstring originalFileName = dir + fileName;
        std::wstring tempFileName = dir + L"temp";

        while(true)
        {
            int ret = rename(convertWstringToString(originalFileName).c_str(), convertWstringToString(tempFileName).c_str());
            if(ret == 0)
                break;      

            Sleep(10);
        }   

        /** File is not open. Rename to original. */
        int ret = rename(convertWstringToString(tempFileName).c_str(), convertWstringToString(originalFileName).c_str());
        if(ret != 0)
            throw std::exception("File rename failed"); 

        return true;
    }
0 голосов
/ 31 июля 2013

это не может быть так сложно, ребята.

сделать это:

try{
File fileout = new File(path + ".xls");
FileOutPutStream out = new FileOutPutStream(fileout);
}
catch(FileNotFoundException e1){

 // if a MS Windows process is already using the file, this exception will be thrown
}
catch(Exception e){

}
0 голосов
/ 23 декабря 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...