是readdir,还是readdir_r

         readdir的原型如下:

struct dirent *readdir(DIR *dirp);

         因为内部使用了静态数据,所以readdir被认为不是线程安全的函数,POSIX[i]标准这样描述:

         The application shall not modify the structure to which the return value of readdir() points, nor any storage areas pointed to by pointers within the structure. The returned pointer, and pointers within the structure, might be invalidated or the structure or the storage areas might be overwritten by a subsequent call to readdir() on the same directory stream. They shall not be affected by a call to readdir() on a different directory stream.

         If a file is removed from or added to the directory after the most recent call to opendir() or rewinddir(),whether a subsequent call to readdir() returns an entry for that file is unspecified.

         The readdir() function need not be thread-safe.

 

         因此才有了readdir_r函数的出现,它的原型如下:

int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);

         readdir_r将返回结果填充到调用者提供的entry缓冲区中,保证了它的线程安全性。

 

         然而,在GNU的官方文档[ii]中,有下面的描述:

         In POSIX.1-2008, readdir is not thread-safe. In the GNU C Library implementation, it is safe to call readdir concurrently on different dirstreams, but multiple threads accessing the same dirstream result in undefined behavior. readdir_r is a fully thread-safe alternative, but suffers from poor portability (see below). It is recommended that you use readdir, with externallocking if multiple threads access the same dirstream.

 

         Portability Note: It is recommended to use readdir instead of readdir_r for the following reasons:

         On systems which do not define NAME_MAX, it may not be possible to use readdir_r safely because the caller does not specify the length of the buffer for the directory entry.

         On some systems,readdir_r cannot read directory entries with very long names. If such a name is encountered, the GNU C Library implementation of readdir_r returns with an error code of ENAMETOOLONG after the final directory entry has been read. On other systems, readdir_r may return successfully, but the d_name member may not be NUL-terminated or may be truncated.

         POSIX-1.2008 does not guarantee that readdir is thread-safe, even when access to the same dirstream is serialized. But in current implementations(including the GNU C Library), it is safe to call readdir concurrently on different dirstreams, so there is no need to use readdir_r in most multi-threaded programs. In the rare case that multiple threads need to read from the same dirstream, it is still better to use readdir and external synchronization.

         It is expected that future versions of POSIX will obsolete readdir_r and mandate the level of thread safety for readdir which is provided by the GNU C Library and other implementations today.

         尽管POSIX中不保证readdir是线程安全的,但是在目前的实现中(包括GUN  C库),在不同的dirstream上(dirp)同时调用readdir能够保证是安全的。因此,多线程程序中其实没必要使用readdir_r,即使在极少场景下,多个线程中需要使用相同的dirstream时,使用readdir以及外部同步手段(加锁),也会是更好的选择。预计在未来版本的POSIX标准中,将会废弃readdir_r。

         除了线程安全方面的考虑,没必要使用readdir_r之外,readdir_r还有其他可移植上的缺点,比如某些系统上readdir_r无法处理有很长名字的目录项。

         而且,结构体dirent中只有d_name是在POSIX中有明确规定的,它长度还是未指定的(在Linux中,结构体dirent中的d_name,具有明确的数组长度,为256),因此,某些系统中,为了使用readdir_r,必须像下面这样分配entry的内存:

name_max = pathconf(dirpath, _PC_NAME_MAX);
if (name_max == -1)         /* Limit not defined, or error */
name_max = 255;         /* Take a guess */
len = offsetof(struct dirent, d_name) + name_max + 1;
entryp = malloc(len);

         但是这种方式也有问题[iii]

 

         因此,结论就是:

只要不是多个线程使用相同的dirstream,就尽可能的使用readdir,它其实更简单且更安全。

 

参考:

http://pubs.opengroup.org/onlinepubs/9699919799/

https://www.gnu.org/software/libc/manual/html_mono/libc.html#Reading_002fClosing-Directory

http://elliotth.blogspot.co.uk/2012/10/how-not-to-use-readdirr3.html

 



[i] http://pubs.opengroup.org/onlinepubs/9699919799/

[ii] https://www.gnu.org/software/libc/manual/html_mono/libc.html#Reading_002fClosing-Directory

[iii] elliotth's blog: How (not) to usereaddir_r(3):http://elliotth.blogspot.co.uk/2012/10/how-not-to-use-readdirr3.html

转载于:https://www.cnblogs.com/gqtcgq/p/7247082.html

1.创建文件夹: #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <iostream> using namespace std; int main() { string folder_name = "new_folder"; mkdir(folder_name.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); //创建文件夹 return 0; } 2.复制文件: #include <stdio.h> #include <stdlib.h> int main() { FILE *fp1, *fp2; //定义两个文件指针 char ch; fp1 = fopen("file1.txt", "r"); //打开要复制的文件 fp2 = fopen("file2.txt", "w"); //打开要复制到的文件 while ((ch = fgetc(fp1)) != EOF) { fputc(ch, fp2); //复制文件 } fclose(fp1); fclose(fp2); return 0; } 3.移动文件: #include <stdio.h> #include <stdlib.h> int main() { char old_path[100] = "old_folder/file1.txt"; char new_path[100] = "new_folder/file1.txt"; int result = rename(old_path, new_path); //移动文件 if (result == 0) { printf("移动成功\n"); } else { printf("移动失败\n"); } return 0; } 4.删除文件夹: #include <unistd.h> #include <stdio.h> int main() { char folder_name[100] = "new_folder"; int result = rmdir(folder_name); //删除文件夹 if (result == 0) { printf("删除成功\n"); } else { printf("删除失败\n"); } return 0; } 5.显示文件夹中的内容: #include <dirent.h> #include <stdio.h> int main() { DIR *dir; struct dirent *ent; char folder_name[100] = "new_folder"; dir = opendir(folder_name); //打开文件夹 while ((ent = readdir(dir)) != NULL) { printf("%s\n", ent->d_name); //遍历文件夹中的文件 } closedir(dir); return 0; } 6.查看文件内容: #include <stdio.h> int main() { FILE *fp; char ch; fp = fopen("file1.txt", "r"); //打开文件 while ((ch = fgetc(fp)) != EOF) { printf("%c", ch); //输出文件内容 } fclose(fp); return 0; } 7.修改文件权限: #include <sys/stat.h> #include <stdio.h> int main() { char file_name[100] = "file1.txt"; chmod(file_name, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); //修改文件权限 return 0; } 8.搜索文件: #include <dirent.h> #include <stdio.h> #include <string.h> int main() { DIR *dir; struct dirent *ent; char folder_name[100] = "new_folder"; char search_name[100] = "file1.txt"; dir = opendir(folder_name); //打开文件夹 while ((ent = readdir(dir)) != NULL) { if (strcmp(ent->d_name, search_name) == 0) //搜索文件 { printf("找到文件:%s\n", ent->d_name); break; } } closedir(dir); return 0; }将上述代码整合成一个完整的程序代码
最新发布
05-31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值