Программно переименовать открытый файл в Windows - PullRequest
14 голосов
/ 22 августа 2011

Я портирую приложение Unix C на Windows. Это приложение переименовывает файлы, когда они открыты, что прекрасно в Unix, но, очевидно, не работает в Windows. Отслеживание всех переименований, чтобы убедиться, что я закрою файл, затем снова открою и снова буду искать, было бы больно.

Учитывая, что Windows Explorer позволяет переименовывать файл во время использования, я удивляюсь, почему я не могу заставить это работать. Я пытался с переименовать и MoveFile в C и System.IO.File.Move в C #. Во всех случаях происходит сбой с ошибкой «Отказано в доступе» (в частности, ошибка, возвращаемая GetLastError (): «Процесс не может получить доступ к файлу, поскольку он используется другим процессом»)

Советы

Я также пытался открыть файл для обмена с _sopen. Это тоже не сработало (та же ошибка).

Рабочий код C # благодаря Стефану:

string orig_filename = "testrenamesharp-123456";
string dest_filename = "fancynewname.txt";
Byte[] info = new UTF8Encoding(true).GetBytes("This is to test the OpenWrite method.");
var fs = new FileStream(orig_filename, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite | FileShare.Delete);
fs.Write(info, 0, info.Length);
File.Move(orig_filename, dest_filename);
fs.Close();

Рабочий образец C:

const char* filename = "testrename-XXXXXX";
const char* dest_filename = "fancynewname.txt";

/* The normal POSIX C functions lock the file */
/* int fd = open(filename, O_RDWR | O_CREAT, _S_IREAD | _S_IWRITE); */ /* Fails */
/* int fd = _sopen(filename, O_RDWR | O_CREAT, _SH_DENYNO, _S_IREAD | _S_IWRITE); */ /* Also fails */

/* We need to use WINAPI + _open_osfhandle to be able to use 
   file descriptors (instead of WINAPI handles) */
HANDLE hFile = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL );
if( INVALID_HANDLE_VALUE == hFile) {
    ErrorExit(TEXT("CreateFile"));
}

int fd = _open_osfhandle((long int)hFile, _O_CREAT | _O_RDWR | _O_TEMPORARY);
if( -1 == fd ) {
    perror("open");
}

int resw = write(fd, buf, strlen(buf));
if(-1 == resw) {
    perror("write");
}

if( 0 == access(dest_filename, F_OK)) {
    perror("access");
}

/* Now try to rename it - On Windows, this fails */
int resr = rename(filename, dest_filename);
if( -1 == resr) {
    perror("rename");
}

int resc = close(fd);
if( -1 == resc ) {
    perror("close");
}

Ответы [ 2 ]

16 голосов
/ 22 августа 2011

Переименование требует, чтобы рассматриваемый файл был открыт с общим доступом FileShare.Delete . Если этот флаг общего ресурса отсутствует, вы не можете переименовать / переместить файл, пока он еще открыт.

4 голосов
/ 22 августа 2011

Зависит от того, как файл был открыт.Если файл открывается с блокировкой, вы не можете написать или переименовать его.Такие инструменты, как Notepad ++, открывают файлы, не блокируя его.Если вы тот, кто открывает и редактирует его, вы также можете сделать это:

http://balajiramesh.wordpress.com/2008/07/16/using-streamreader-without-locking-the-file-in-c/

Код в статье показывает, как использовать FileStream с параметрами FileShare:

using(FileStream fs = new FileStream(@”c:\test.txt”, FileMode.Open, FileAccess.Read,FileShare.ReadWrite))
{
    StreamReader sr = new StreamReader(fs);
    txtContents.Text = sr.ReadToEnd();
    sr.Close();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...