Удалить открытый файл в Windows (создание анонимного файла)?

Под Linux моя программа будет делать что-то вроде этого:

  • Процесс 1 открывает файл (например, отображая его в память). Назовем этот файл #1
  • Процесс 2 разъединяет файл и создает новый файл с тем же именем. Назовем этот файл#2.
  • Процесс 1 продолжает работать с файлом №1. При закрытии он удаляется (поскольку на него нет ссылок). Процесс 1 продолжает работать с содержимым файла №1 и не видит содержимого файла №2.
  • Когда оба процесса завершились, файл №2 остается на диске.

Я хочу добиться такой же семантики в Windows. Прочитав этот вопрос , я думаю, что FILE_SHARE_DELETE делает в основном это. Достаточно ли открыть файл с помощью FILE_SHARE_DELETE или мне нужно подумать о чем-то еще?

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

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


person Krumelur    schedule 31.03.2015    source источник
comment
Нет, FILE_SHARE_DELETE этим не занимается. Файл не будет удален, пока процесс 1 не закроет его, поэтому процесс 2 не сможет создать новый файл с тем же именем.   -  person Harry Johnston    schedule 01.04.2015
comment
Второй процесс должен иметь возможность переименовать файл, затем удалить его, а затем создать новый файл с тем же именем. (Я немного не понимаю правила, определяющие, когда вы можете или не можете переименовывать используемый файл. Но я думаю, что это сработает.)   -  person Harry Johnston    schedule 01.04.2015
comment
Я не понимаю ваш первый вариант использования: ваш пример противоречит вашему описанию, поскольку разные версии файла конфигурации не являются несвязанными. (Если файлы действительно не связаны между собой, правильное - и переносимое! - решение состоит в том, чтобы файлы имели уникальные имена.) Ваш второй вариант использования, как описано, определенно невозможен в Windows, поскольку не существует такой вещи, как безымянный файл.   -  person Harry Johnston    schedule 03.04.2015
comment
Я не думаю, что существует какой-то один портативный подход, идеально подходящий для всех возможных вариантов использования. Но если вы используете FILE_SHARE_DELETE и заменяете удаление на переименование, а затем удаляете, это должно работать приемлемо хорошо для большинства целей. (Конечно, вы можете переместить файл, а также переименовать его, чтобы охватить случаи использования, когда пользователь может смотреть на исходный каталог и может быть смущен или раздражен временными файлами.)   -  person Harry Johnston    schedule 03.04.2015
comment
Я имел в виду, что содержимое файла не имеет отношения. В этом случае имя файла будет иметь особое значение. Я думаю, вы правы, что мне также нужно переименовать файл. Это именно те подводные камни, которые я пытаюсь найти.   -  person Krumelur    schedule 04.04.2015
comment
О, вы просто имеете в виду, что содержимое файла, записанное одной программой, не зависит от содержимого файла, записанного другой?   -  person Harry Johnston    schedule 04.04.2015
comment
Точно. Думайте об этом как о транзакционном, моментальном обновлении файла. Процесс продолжит видеть файл таким, каким он был при первом открытии дескриптора. В этом случае путь к файлу будет использоваться как своего рода контракт. Я попытался перефразировать пример.   -  person Krumelur    schedule 04.04.2015


Ответы (1)


Этого можно добиться, используя комбинацию вызовов CreateFile, CreateFileMapping и MapViewOfFile. MapViewOfFile предоставит вам отображаемый в памяти буфер файла, поддерживаемый файлом на диске.

Следующий код при выполнении из разных процессов запишет идентификатор последнего закрывающего процесса в файл c:\temp\temp.txt.

int main()
{
	TCHAR szMsg[256];
	HANDLE hMapFile;
	LPCTSTR pBuf;

	HANDLE hFile = CreateFileW(
		L"C:\\Temp\\temp.txt", 
		GENERIC_WRITE|GENERIC_READ, 
		FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE, 
		NULL, 
		CREATE_ALWAYS, 
		FILE_ATTRIBUTE_NORMAL,NULL);


	hMapFile = CreateFileMapping(
		hFile,					 // Handle of file opened with rw access
		NULL,                    // default security
		PAGE_READWRITE,          // read/write access
		0,                       // maximum object size (high-order DWORD)
		BUF_SIZE,                // maximum object size (low-order DWORD)
		szName);                 // name of mapping object

	if (hMapFile == NULL)
	{
		printf( "Could not create file mapping object (%d).\n", GetLastError());
		return 1;
	}
	pBuf = (LPTSTR) MapViewOfFile(hMapFile,   // handle to map object
		FILE_MAP_ALL_ACCESS, // read/write permission
		0,
		0,
		BUF_SIZE);

	if (pBuf == NULL)
	{
		printf("Could not map view of file (%d).\n", GetLastError());
		CloseHandle(hMapFile);
		return 1;
	}
	
	wsprintfW(szMsg, L"This is process id %d", GetCurrentProcessId());
	CopyMemory((PVOID)pBuf, szMsg, (wcslen(szMsg) * sizeof(TCHAR)));

	MessageBoxW(NULL, szMsg, L"Check", MB_OK);

	UnmapViewOfFile(pBuf);
	CloseHandle(hMapFile);
	CloseHandle(hFile);
	return 0;


}

Убедитесь, что вы открываете файл с доступом GENERIC_READ|GENERIC_WRITE и разрешаете доступ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE для последующих открытий.

Также обратите внимание на использование CREATE_ALWAYS в CreateFile, которая будет удалять старый файл и открывать новый каждый раз, когда вызывается CreateFile. Это эффект «разъединения», о котором вы говорите.

Код, вдохновленный Создание именованной общей памяти в MSDN.

person ExceptionalHandler    schedule 31.03.2015
comment
Спасибо! Есть ли конкретная причина, по которой используется отображение памяти, или обычный поток ввода-вывода также будет работать? Обратите внимание, что я не хочу делиться памятью или данными. - person Krumelur; 31.03.2015
comment
Это не сработает. При втором запуске CreateFile завершится ошибкой, так как он не сможет создать новый файл с тем же именем, что и у существующего. - person Harry Johnston; 01.04.2015
comment
@Krumelur, отображение памяти используется, чтобы избежать потокового ввода-вывода в файле, который может измениться на диске. Windows предоставляет файлы с отображением памяти, чтобы каждый процесс мог по-своему воспринимать файл, не беспокоясь о том, что находится на диске. - person ExceptionalHandler; 01.04.2015
comment
Кроме того, когда записи в файл совместно используются потоками или процессами, вы можете прочитать несогласованные данные из файла. Первая строка может быть из старой версии файла, а вторая строка из более новой версии... - person ExceptionalHandler; 01.04.2015
comment
@ExceptionalHandler Совместное использование данных - это не то, что мне нужно, я ищу семантику Linux, где первый файл становится безымянным (и будет удален после его закрытия). - person Krumelur; 02.04.2015