2011-08-22 19 views
12

Przesyłam aplikację Unix C do systemu Windows. Ta aplikacja zmienia nazwy plików, gdy są otwarte, co jest doskonale w Unix, ale najwyraźniej nie działa w systemie Windows. Śledzenie wszystkich nazw, aby upewnić się, że zamknę plik, a następnie ponownie go otworzę i spróbuję ponownie, będzie bolesne.Programowa zmiana nazwy otwartego pliku w systemie Windows

Biorąc pod uwagę, że Eksplorator Windows pozwala na zmianę nazwy pliku w trakcie jego używania, zastanawiam się, dlaczego nie mogę go uruchomić. Próbowałem z rename i MoveFile w C i System.IO.File.Move w C#. W każdym przypadku nie działa z błędem "Odmowa uprawnień" (konkretnie błąd zwracany przez GetLastError() to "Proces nie może uzyskać dostępu do pliku, ponieważ jest on używany przez inny proces")

Wskazówki?

Próbowałem również otworzyć plik do udostępniania za pomocą _sopen. To też nie działa (ten sam błąd).

roboczy kod C# dzięki Stefan:

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(); 

robocza C przykładowe:

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"); 
} 
+0

jakiego rodzaju awarie doświadczasz? – StevenV

+0

Odmowa uprawnień. – pgquiles

+2

Eksplorator Windows pozwala zmienić nazwę pliku (zablokowanego), gdy jest on używany? Od kiedy? –

Odpowiedz

12

Zmiana nazwy wymaga że dany plik został otwarty z udostępnianiem FileShare.Delete. Jeśli brakuje tej flagi udziału, nie można zmienić nazwy/przenieść pliku, gdy jest on nadal otwarty.

+0

Dziękuję! To działa w C#, teraz muszę tylko znaleźć odpowiednik FileShare.Delete w C: -/ – pgquiles

+1

Zobacz http://msdn.microsoft.com/en-us/library/aa363858%28v=vs.85% 29.aspx w szczególności parametr dwShareMode (FILE_SHARE_DELETE) – Joe

+0

@Joe: Dziękuję, właśnie znalazłem o tym i zakończyłem testowanie. Zmontowałem próbkę C. Potrzebowałem też _open_osfhandle, ponieważ aplikacja używa plików z nazwami plików. – pgquiles

4

To zależy od tego, jak plik został otwarty. Jeśli plik jest otwarty z blokadą, nie możesz go zmienić ani zmienić. Narzędzia takie jak Notepad ++ otwierają pliki bez ich blokowania. Jeśli jesteś osobą, która otwiera i edytuje go, można to zrobić za:

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

Kod w artykule pokazuje jak używać FileStream z opcji 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(); 
} 
+0

To nie działa, zobacz moją próbkę C# – pgquiles

Powiązane problemy