我有一個包含數千個檔案的目錄,所有檔案都具有一般格式,***-***.txt
除了一個具有 format 的檔案***.txt
,我保證它恰好有一個 & ,其確切名稱我無法知道。
我想知道是否可以在不遍歷所有目錄、僅使用 C 或 Linux 函式且不呼叫system()
.
uj5u.com熱心網友回復:
如前所述,沒有辦法避免對檔案名進行迭代。好訊息是這真的沒關系。即使有成千上萬的條目(哇?!)它也不應該花費太多時間,所以如果你只需要做一次,你就很好了。
C
// Life is easy in C
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
fs::path find_magic_file( const fs::path directory )
{
for (auto & entry : fs::directory_iterator( directory ))
if (entry.path().stem().string().find( '-' ) == std::string::npos)
return entry.path();
return "";
}
int main( int num_directories, char ** directory_names )
{
for (int n = 1; n < num_directories; n = 1)
{
auto filepath = find_magic_file( directory_names[n] );
if (!filepath.empty())
std::cout << filepath.string() << "\n";
}
}
C
// C requires you to recur to the OS facilities directly
// This example handles Windows and Linux/POSIX systems
#ifdef _WIN32
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <iso646.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
char * find_magic_file( const char * directory )
{
WIN32_FIND_DATA entry;
char * dirname = malloc( strlen( directory ) 5 );
if (!dirname) return NULL;
HANDLE h = FindFirstFile( strcat( strcpy( dirname, directory ), "/*.*" ), &entry );
if (h == INVALID_HANDLE_VALUE) return NULL;
while ((strcmp( entry.cFileName, "." ) == 0)
or (strcmp( entry.cFileName, ".." ) == 0)
or (strchr( entry.cFileName, '-' )))
if (!FindNextFile( h, &entry ))
break;
FindClose( h );
free( dirname );
if (strchr( entry.cFileName, '-' )) return NULL;
char * filepath = calloc( strlen( directory ) 1 strlen( entry.cFileName ) 1, 1 );
if (filepath) strcat( strcat( strcpy( filepath, directory ), "/" ), entry.cFileName );
return filepath;
}
#else
#include <dirent.h>
#include <sys/types.h>
char * find_magic_file( const char * directory )
{
char * filepath = NULL;
DIR * dir = opendir( directory );
if (dir)
{
struct dirent * entry;
while ((entry = readdir( dir )))
{
if (!strchr( entry->d_name, '-' )
and (strcmp( entry->d_name, "." ) != 0)
and (strcmp( entry->d_name, ".." ) != 0))
{
filepath = malloc( strlen( directory ) 1 strlen( entry->d_name ) 1 );
if (filepath) strcat( strcat( strcpy( filepath, directory ), "/" ), entry->d_name );
break;
}
}
closedir( dir );
}
return filepath;
}
#endif
int main( int num_directories, char ** directory_names )
{
for (int n = 1; n < num_directories; n = 1)
{
char * filepath = find_magic_file( directory_names[n] );
if (filepath)
{
puts( filepath );
free( filepath );
}
}
}
您會注意到main()
兩種語言之間唯一真正的區別是find_magic_file()
.
uj5u.com熱心網友回復:
在 Linux 中,您可以使用 POSIX.1 scandir()函式,以及一個過濾器函式,該函式拒絕帶有破折號的檔案名。
這樣,掃描/迭代是在 C 庫中以適合手頭作業系統的方式完成的,并且如果在掃描期間重命名檔案,則不應混淆。如果將無破折號檔案重命名為破折號檔案,而將另一個破折號檔案重命名為無破折號名稱,則恰好在目錄掃描期間,可能找不到任何一個名稱。(并且,如果它們以相反的順序完成,則可以看到兩個名稱。)
這是一個示例程式,具有完整的錯誤檢查:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
static int dashless_filter(const struct dirent *ent)
{
/* Reject file names that begin with a dot '.' ("hidden" files) */
if (ent->d_name[0] == '.')
return 0;
/* Reject file names with dash in them */
if (strchr(ent->d_name, '-'))
return 0;
return 1;
}
char *dashless(const char *dirpath)
{
struct dirent **list = NULL;
char *result = NULL;
int num, err;
/* Return NULL if dirpath is null or empty */
if (!dirpath || !*dirpath) {
errno = ENOTDIR;
return NULL;
}
do {
num = scandir(dirpath, &list, dashless_filter, NULL);
if (num == -1) {
err = errno; /* errno set by scandir() */
break;
}
if (num < 1 || !list || !list[0] || list[0]->d_name[0] == '\0') {
err = ENOENT; /* No matching files found */
break;
} else
if (num > 1) {
err = EMFILE; /* More than one matching file found. */
break;
}
result = strdup(list[0]->d_name);
if (!result) {
err = ENOMEM;
} else {
err = 0;
}
} while (0);
/* Free all entries in the list, */
while (num-->0)
free(list[num]);
/* and the list itself. */
free(list);
errno = err;
return result;
}
int main(int argc, char *argv[])
{
int status = EXIT_SUCCESS;
int arg;
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
const char *arg0 = (argc > 0 && argv && argv[0] && argv[0][0]) ? argv[0] : "(this)";
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", arg0);
fprintf(stderr, " %s DIRECTORY [ DIRECTORY ... ]\n", arg0);
fprintf(stderr, "\n");
fprintf(stderr, "This program reports if each specified directory contains\n");
fprintf(stderr, "a single file without a dash '-' in its name.\n");
fprintf(stderr, "\n");
return EXIT_SUCCESS;
}
for (arg = 1; arg < argc; arg ) {
char *filepath = dashless(argv[arg]);
if (filepath) {
printf("%s: %s\n", argv[arg], filepath);
free(filepath);
} else {
if (errno == EMFILE)
fprintf(stderr, "%s: Multiple dashless files exist.\n", argv[arg]);
else
fprintf(stderr, "%s: %s.\n", argv[arg], strerror(errno));
status = EXIT_FAILURE;
}
}
return status;
}
請注意,它顯式檢查單個檔案名。
如果生成檔案的應用程式或腳本也確實創建了一個具有固定、已知名稱的硬鏈接到一個無破折號檔案,不管它可能是什么,那會更好。這樣,人們總是可以使用固定的符號鏈接/硬鏈接名稱,并且如果重命名無破折號檔案,則不會有任何競爭視窗在此期間將發現一個無破折號檔案或兩個無破折號檔案。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/470632.html