在 Windows 上以编程方式重命名打开的文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7147577/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 17:54:51  来源:igfitidea点击:

Programmatically rename open file on Windows

c#cwindowslinuxwinapi

提问by pgquiles

I am porting a Unix C application to Windows. This application renames files while they are open, which is perfectly fine on Unix but apparently it does not work on Windows. Tracing all the renames to make sure I close the file, then reopen and seek again would be painful.

我正在将 Unix C 应用程序移植到 Windows。这个应用程序在打开文件时重命名文件,这在 Unix 上完全没问题,但显然它在 Windows 上不起作用。跟踪所有重命名以确保我关闭文件,然后重新打开并再次查找会很痛苦。

Given that Windows Explorer allows to rename a file while is in use, I wonder why I cannot get this to work. I have tried with renameand MoveFilein C, and System.IO.File.Move in C#. It fails in all cases with a "Permission denied" error (specifically, the error returned by GetLastError() is "The process cannot access the file because it is being used by another process")

鉴于 Windows 资源管理器允许在使用时重命名文件,我想知道为什么我不能让它工作。我尝试过在 C 中使用renameMoveFile,在 C# 中使用 System.IO.File.Move。它在所有情况下都失败并显示“权限被拒绝”错误(具体来说,GetLastError() 返回的错误是“进程无法访问文件,因为它正在被另一个进程使用”)

Tips?

提示?

I have also tried to open the file for sharing with _sopen. It didn't work either (same error).

我还尝试打开文件以与 _sopen 共享。它也不起作用(同样的错误)。

Working C# code thanks to Stefan:

感谢 Stefan 工作的 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();

Working C sample:

工作 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");
}

回答by Stefan

Renaming requires that the file in question was opened with FileShare.Deletesharing. If that share flag is missing, you can not rename/move the file while it is still open.

重命名要求使用FileShare.Delete共享打开相关文件。如果缺少该共享标志,则无法在文件仍处于打开状态时重命名/移动文件。

回答by UrbanEsc

It depends on how the file was opened. If a file is opened with lock, you cant write or rename it. Tools like Notepad++ open files without locking it. If you are the one who opens and edits it, you can do that too:

这取决于文件的打开方式。如果文件以锁定方式打开,则无法写入或重命名它。Notepad++ 之类的工具可以在不锁定的情况下打开文件。如果您是打开和编辑它的人,您也可以这样做:

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

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

The code in the article shows how to use a FileStream with FileShare options:

文章中的代码展示了如何使用带有 FileShare 选项的 FileStream:

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