stdio的remove()并不总是按时删除

发布于 2024-08-28 06:27:34 字数 1258 浏览 9 评论 0原文

对于一项特定的作业,我正在使用标准 C 下的顺序文件实现一个基本数据存储系统,该系统一次不能加载超过 1 条记录。因此,基本部分是创建一个新文件,其中存储我们对原始记录所做的任何操作的结果。前一个文件被重命名,并以工作名称创建一个新文件。该代码是在 Windows 7 上使用 MinGW 5.1.6 编译的。

问题是,这个特定版本的代码(我的函数周围有几乎相同的版本)并不总是删除旧文件,因此重命名失败因此存储的数据被 fopen() 擦除。

FILE *archivo, *antiguo;

remove("IndiceNecesidades.old");  // This randomly fails to work in time.
rename("IndiceNecesidades.dat", "IndiceNecesidades.old"); // So rename() fails.

antiguo = fopen("IndiceNecesidades.old", "rb");
// But apparently it still gets deleted, since this turns out null (and I never find the .old in my working folder after the program's done).
archivo = fopen("IndiceNecesidades.dat", "wb"); // And here the data gets wiped.

基本上,只要 .old 以前存在,就有可能没有及时删除以便 rename() 成功生效。内部和外部都不可能发生名称冲突。

奇怪的是,它只适用于这个特定的文件。除了名称更改为 Necesidades.dat(发生在 3 个不同的函数中)之外,其他相同的片段都可以正常工作。

// I'm yet to see this snippet fail.
FILE *antiguo, *archivo;

remove("Necesidades.old");
rename("Necesidades.dat", "Necesidades.old");

antiguo = fopen("Necesidades.old", "rb");
archivo = fopen("Necesidades.dat", "wb");

关于为什么会发生这种情况的任何想法,和/或如何确保remove()命令在执行rename()时生效? (我想只要 fopen() 返回一个非空指针,就使用 while 循环来强制再次调用 remove() ,但这听起来像是由于删除请求或其他东西溢出操作系统而导致崩溃。)

For a particular piece of homework, I'm implementing a basic data storage system using sequential files under standard C, which cannot load more than 1 record at a time. So, the basic part is creating a new file where the results of whatever we do with the original records are stored. The previous file's renamed, and a new one under the working name is created. The code's compiled with MinGW 5.1.6 on Windows 7.

Problem is, this particular version of the code (I've got nearly-identical versions of this floating around my functions) doesn't always remove the old file, so the rename fails and hence the stored data gets wiped by the fopen().

FILE *archivo, *antiguo;

remove("IndiceNecesidades.old");  // This randomly fails to work in time.
rename("IndiceNecesidades.dat", "IndiceNecesidades.old"); // So rename() fails.

antiguo = fopen("IndiceNecesidades.old", "rb");
// But apparently it still gets deleted, since this turns out null (and I never find the .old in my working folder after the program's done).
archivo = fopen("IndiceNecesidades.dat", "wb"); // And here the data gets wiped.

Basically, anytime the .old previously exists, there's a chance it's not removed in time for the rename() to take effect successfully. No possible name conflicts both internally and externally.

The weird thing's that it's only with this particular file. Identical snippets except with the name changed to Necesidades.dat (which happen in 3 different functions) work perfectly fine.

// I'm yet to see this snippet fail.
FILE *antiguo, *archivo;

remove("Necesidades.old");
rename("Necesidades.dat", "Necesidades.old");

antiguo = fopen("Necesidades.old", "rb");
archivo = fopen("Necesidades.dat", "wb");

Any ideas on why would this happen, and/or how can I ensure the remove() command has taken effect by the time rename() is executed? (I thought of just using a while loop to force call remove() again so long as fopen() returns a non-null pointer, but that sounds like begging for a crash due to overflowing the OS with delete requests or something.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

路弥 2024-09-04 06:27:34

所以突然间,在读完 Scott 提到的权限后,我想到了“Permission Denied”并应用了一些 Google。 事实证明这是一个很常见的问题,如果模糊,则错误。
caf 是对的,它在另一段代码中。也就是说,我忘记在用于显示内容的函数中关闭同一个文件。由于我没有追踪那个特定的细节,所以它看起来是随机的。

免责声明:每周的数学作业会占用很少的睡眠时间。 ØØ

So suddenly, after reading Scott's mention of permissions, I thought about "Permission Denied" and applied some Google. Turned out it's a pretty common, if obscure, error.
caf was right, it was in another piece of code. Namely, I had forgotten to fclose that same file in the function meant to show the contents. Since I wasn't tracking that particular detail, it appeared to be random.

Disclaimer: Weekly math assigments make for very little sleeptime. ¬¬

别再吹冷风 2024-09-04 06:27:34

这听起来很奇怪,当你说相同的代码使用不同的文件名可以正常工作时更是如此 - 我强烈怀疑你的代码中其他地方有错误。但是,您应该可以通过重命名要删除的文件来解决此问题:

rename("IndiceNecesidades.old", "IndiceNecesidades.older");
remove("IndiceNecesidades.older");
rename("IndiceNecesidades.dat", "IndiceNecesidades.old");

That sounds quite strange, and even more so when you say that the same code works OK with a different filename - I would strongly suspect a bug elsewhere in your code. However, you should be able to work around it by renaming the file you want to remove:

rename("IndiceNecesidades.old", "IndiceNecesidades.older");
remove("IndiceNecesidades.older");
rename("IndiceNecesidades.dat", "IndiceNecesidades.old");
巷子口的你 2024-09-04 06:27:34

检查 remove() 函数是否有错误可能是个好主意。 man remove表示该函数成功时返回0,失败时返回-1,设置errno来记录错误。尝试将调用替换为

if (remove("IndiceNecesidades.old") != 0){
   perror("remove(\"IndiceNecesidades.old\") failed");
}

which 应该给出错误消息,说明失败的原因。

此外,似乎没有必要删除

ma​​n rename()

rename() 系统调用会导致
名为旧的链接将被重命名为新的。
如果存在新的,则首先将其删除。
新旧必须相同
类型(也就是说,两者都必须是
目录或非目录)和
必须驻留在同一文件系统上。

rename() 系统调用保证
new 的实例总是
存在,即使系统崩溃
在操作过程中。

如果 old 的最后一个组件是
符号链接,符号链接是
重命名,而不是文件或目录
它指向哪个。

如果出现以下情况,EPERM 将被退回:

[EPERM] 目录
包含旧的被标记为粘性的,并且
既不是包含目录也不是
旧的由有效用户拥有
身份证号。

[EPERM] 新文件
存在,目录包含新的
被标记为粘性的,并且
包含目录或新目录都被拥有
通过效果-
主动用户 ID。

所以下一步是检查您是否拥有包含目录的权限

It would probably be a good idea to check the remove() function for errors. man remove says that the function returns 0 on success and -1 on failure, setting errno to record the error. Try replacing the call with

if (remove("IndiceNecesidades.old") != 0){
   perror("remove(\"IndiceNecesidades.old\") failed");
}

which should give an error message saying what failed.

Further, it doesn't appear that the remove is neccessary

man rename()

The rename() system call causes the
link named old to be renamed as new.
If new exists, it is first removed.
Both old and new must be of the same
type (that is, both must be either
directories or non-directories) and
must reside on the same file system.

The rename() system call guarantees
that an instance of new will always
exist, even if the system should crash
in the middle of the operation.

If the final component of old is a
symbolic link, the symbolic link is
renamed, not the file or directory to
which it points.

EPERM will be returned if:

[EPERM] The directory
containing old is marked sticky, and
neither the containing directory nor
old are owned by the effective user
ID.

[EPERM] The new file
exists, the directory containing new
is marked sticky, and neither the
containing directory nor new are owned
by the effec-
tive user ID.

so the next step would be to check you have permissions on the containing directory

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文