Простой поиск текста в C [дубликат]

Вопрос был:

Как вернуть ответ от асинхронного вызова?

, который может быть интерпретирован как:

Как сделать синхронный асинхронный код синхронным?

Решение будет состоять в том, чтобы избежать обратных вызовов и использовать комбинацию Promises и async / await.

Я хотел бы привести пример для запроса Ajax.

(Хотя он может быть записан в Javascript, я предпочитаю писать его на Python и компилировать его в Javascript, используя Transcrypt . Это будет достаточно ясно.)

Позволяет сначала включить использование JQuery, чтобы $ был доступен как S:

__pragma__ ('alias', 'S', '$')

Определить функцию, которая возвращает Promise, в этом случае вызов Ajax:

def read(url: str):
    deferred = S.Deferred()
    S.ajax({'type': "POST", 'url': url, 'data': { },
        'success': lambda d: deferred.resolve(d),
        'error': lambda e: deferred.reject(e)
    })
    return deferred.promise()

Использовать асинхронный код, как если бы он был синхронным:

async def readALot():
    try:
        result1 = await read("url_1")
        result2 = await read("url_2")
    except Exception:
        console.warn("Reading a lot failed")

438
задан herohuyongtao 19 October 2014 в 13:38
поделиться

21 ответ

В небольших и простых задачах я не использую boost, я использую dirent.h, который также доступен для окон:

DIR *dir;
struct dirent *ent;
if ((dir = opendir ("c:\\src\\")) != NULL) {
  /* print all the files and directories within directory */
  while ((ent = readdir (dir)) != NULL) {
    printf ("%s\n", ent->d_name);
  }
  closedir (dir);
} else {
  /* could not open directory */
  perror ("");
  return EXIT_FAILURE;
}

Это всего лишь небольшой заголовочный файл и делает большинство простых вещей вам нужно без использования большого подхода на основе шаблонов, такого как boost (без обид, мне нравится boost!).

Автором уровня совместимости окон является Тони Ронкко. В Unix это стандартный заголовок.

UPDATE 2017:

В C ++ 17 теперь есть официальный способ перечислить файлы вашей файловой системы: std::filesystem. Существует отличный ответ от Shreevardhan ниже с этим исходным кодом:

#include <string>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    std::string path = "/path/to/directory";
    for (auto & p : fs::directory_iterator(path))
        std::cout << p << std::endl;
}

. Рассмотрите вопрос о его ответе, если вы используете подход C ++ 17.

614
ответ дан einpoklum 25 August 2018 в 06:28
поделиться

Вот очень простой код в C++11 с использованием библиотеки boost::filesystem для получения имен файлов в каталоге (исключая имена папок):

#include <string>
#include <iostream>
#include <boost/filesystem.hpp>
using namespace std;
using namespace boost::filesystem;

int main()
{
    path p("D:/AnyFolder");
    for (auto i = directory_iterator(p); i != directory_iterator(); i++)
    {
        if (!is_directory(i->path())) //we eliminate directories
        {
            cout << i->path().filename().string() << endl;
        }
        else
            continue;
    }
}

Вывод выглядит как:

file1.txt
file2.dat
19
ответ дан Bad 25 August 2018 в 06:28
поделиться

System call it!

system( "dir /b /s /a-d * > file_names.txt" );

Затем просто прочитайте файл.

EDIT: Этот ответ следует считать взломом, но он действительно работает (хотя и на платформе конкретный способ), если у вас нет доступа к более элегантным решениям.

1
ответ дан Catalyst 25 August 2018 в 06:28
поделиться

Это сработало для меня. Он записывает файл с именами (без пути) всех файлов. Затем он считывает этот txt-файл и печатает его для вас.

void DisplayFolderContent()
    {

        system("dir /n /b * > file_names.txt");
        char ch;
        std::fstream myStream("file_names.txt", std::fstream::in);
        while (myStream.get(ch))
        {
            std::cout << ch;
        }

    }
-1
ответ дан Cesar Alejandro Montero Orozco 25 August 2018 в 06:28
поделиться

Я рекомендую использовать glob с этой повторно используемой оболочкой. Он генерирует vector<string>, соответствующий путям файлов, которые соответствуют шаблону glob:

#include <glob.h>
#include <vector>
using std::vector;

vector<string> globVector(const string& pattern){
    glob_t glob_result;
    glob(pattern.c_str(),GLOB_TILDE,NULL,&glob_result);
    vector<string> files;
    for(unsigned int i=0;i<glob_result.gl_pathc;++i){
        files.push_back(string(glob_result.gl_pathv[i]));
    }
    globfree(&glob_result);
    return files;
}

, который затем можно вызвать с обычным шаблоном шаблона системы, например:

vector<string> files = globVector("./*");
26
ответ дан Chris Redford 25 August 2018 в 06:28
поделиться

Для решения только C, пожалуйста, проверьте это. Для этого требуется только дополнительный заголовок:

https://github.com/cxong/tinydir

tinydir_dir dir;
tinydir_open(&dir, "/path/to/dir");

while (dir.has_next)
{
    tinydir_file file;
    tinydir_readfile(&dir, &file);

    printf("%s", file.name);
    if (file.is_dir)
    {
        printf("/");
    }
    printf("\n");

    tinydir_next(&dir);
}

tinydir_close(&dir);

Некоторые преимущества перед другими опциями:

  • Он переносится - обертывает POSIX dirent и Windows FindFirstFile
  • Он использует readdir_r, где доступно, что означает, что он (обычно) threadsafe
  • Поддерживает Windows UTF- 16 через те же UNICODE макросы
  • Это C90, поэтому даже очень древние компиляторы могут использовать его
43
ответ дан congusbongus 25 August 2018 в 06:28
поделиться

К сожалению, стандарт C ++ не определяет стандартный способ работы с файлами и папками таким образом.

Поскольку нет кросс-платформенного способа, лучшим кросс-платформенным способом является использование библиотеки, такой как модуль boost fileystem .

Метод повышения перекрестной платформы :

Следующая функция, заданная пути к каталогу и имени файла, рекурсивно ищет каталог и его подкаталоги для имени файла, возвращает bool, и в случае успеха путь к файл, который был найден.

bool find_file(const path & dir_path,         // in this directory,
               const std::string & file_name, // search for this name,
               path & path_found)             // placing path here if found
{
    if (!exists(dir_path)) 
        return false;

    directory_iterator end_itr; // default construction yields past-the-end

    for (directory_iterator itr(dir_path); itr != end_itr; ++itr)
    {
        if (is_directory(itr->status()))
        {
            if (find_file(itr->path(), file_name, path_found)) 
                return true;
        }
        else if (itr->leaf() == file_name) // see below
        {
            path_found = itr->path();
            return true;
        }
    }
    return false;
}

Источник с указанной выше страницы повышения.


Для систем на основе Unix / Linux:

Вы можете использовать opendir / readdir / closedir .

Пример кода, который выполняет поиск в каталоге для записи `` name '', это:

   len = strlen(name);
   dirp = opendir(".");
   while ((dp = readdir(dirp)) != NULL)
           if (dp->d_namlen == len && !strcmp(dp->d_name, name)) {
                   (void)closedir(dirp);
                   return FOUND;
           }
   (void)closedir(dirp);
   return NOT_FOUND;

Исходный код с приведенных выше справочных страниц.


Для систем на базе Windows:

вы можете использовать Win32 API FindFirstFile / FindNextFile / FindClose .

Следующий пример C ++ показывает минимальное использование FindFirstFile.

#include <windows.h>
#include <tchar.h>
#include <stdio.h>

void _tmain(int argc, TCHAR *argv[])
{
   WIN32_FIND_DATA FindFileData;
   HANDLE hFind;

   if( argc != 2 )
   {
      _tprintf(TEXT("Usage: %s [target_file]\n"), argv[0]);
      return;
   }

   _tprintf (TEXT("Target file is %s\n"), argv[1]);
   hFind = FindFirstFile(argv[1], &FindFileData);
   if (hFind == INVALID_HANDLE_VALUE) 
   {
      printf ("FindFirstFile failed (%d)\n", GetLastError());
      return;
   } 
   else 
   {
      _tprintf (TEXT("The first file found is %s\n"), 
                FindFileData.cFileName);
      FindClose(hFind);
   }
}

Исходный код из вышеуказанных страниц msdn.

212
ответ дан Drise 25 August 2018 в 06:28
поделиться

вы можете получить все прямые файлы в корневом каталоге, используя std :: experimental :: filesystem :: directory_iterator (). Затем прочитайте имя этих файлов путей.

#include <iostream>
#include <filesystem>
#include <string>
#include <direct.h>
using namespace std;
namespace fs = std::experimental::filesystem;
void ShowListFile(string path)
{
for(auto &p: fs::directory_iterator(path))  /*get directory */
     cout<<p.path().filename()<<endl;   // get file name
}

int main() {

ShowListFile("C:/Users/dell/Pictures/Camera Roll/");
getchar();
return 0;
}
1
ответ дан ducPham 25 August 2018 в 06:28
поделиться

Это работает для меня. Извините, если я не могу вспомнить источник. Вероятно, это с man-страницы.

#include <ftw.h>

int AnalizeDirectoryElement (const char *fpath, 
                            const struct stat *sb,
                            int tflag, 
                            struct FTW *ftwbuf) {

  if (tflag == FTW_F) {
    std::string strFileName(fpath);

    DoSomethingWith(strFileName);
  }
  return 0; 
}

void WalkDirectoryTree (const char * pchFileName) {

  int nFlags = 0;

  if (nftw(pchFileName, AnalizeDirectoryElement, 20, nFlags) == -1) {
    perror("nftw");
  }
}

int main() {
  WalkDirectoryTree("some_dir/");
}
2
ответ дан ENHering 25 August 2018 в 06:28
поделиться

Эта реализация реализует вашу цель, динамически заполняя массив строк содержимым указанного каталога.

int exploreDirectory(const char *dirpath, char ***list, int *numItems) {
    struct dirent **direntList;
    int i;
    errno = 0;

    if ((*numItems = scandir(dirpath, &direntList, NULL, alphasort)) == -1)
        return errno;

    if (!((*list) = malloc(sizeof(char *) * (*numItems)))) {
        fprintf(stderr, "Error in list allocation for file list: dirpath=%s.\n", dirpath);
        exit(EXIT_FAILURE);
    }

    for (i = 0; i < *numItems; i++) {
        (*list)[i] = stringDuplication(direntList[i]->d_name);
    }

    for (i = 0; i < *numItems; i++) {
        free(direntList[i]);
    }

    free(direntList);

    return 0;
}
2
ответ дан Giacomo Marciani 25 August 2018 в 06:28
поделиться

Одной функции достаточно, вам не нужно использовать стороннюю библиотеку (для Windows).

#include <Windows.h>

vector<string> get_all_files_names_within_folder(string folder)
{
    vector<string> names;
    string search_path = folder + "/*.*";
    WIN32_FIND_DATA fd; 
    HANDLE hFind = ::FindFirstFile(search_path.c_str(), &fd); 
    if(hFind != INVALID_HANDLE_VALUE) { 
        do { 
            // read all (real) files in current folder
            // , delete '!' read other 2 default folder . and ..
            if(! (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
                names.push_back(fd.cFileName);
            }
        }while(::FindNextFile(hFind, &fd)); 
        ::FindClose(hFind); 
    } 
    return names;
}

PS: как упоминалось @Sebastian, вы можете изменить *.* на *.ext, чтобы получить только EXT-файлы (т. е. определенного типа) в этом каталоге.

73
ответ дан herohuyongtao 25 August 2018 в 06:28
поделиться

GNU Manual FTW

http://www.gnu.org/software/libc/manual/html_node/Simple-Directory-Lister.html#Simple-Directory-Lister

Кроме того, иногда бывает хорошо перейти прямо к источнику (каламбур). Вы можете многому научиться, глядя на внутренности некоторых из наиболее распространенных команд в Linux. Я установил простое зеркало ядра ядра GNU на github (для чтения).

https://github.com/homer6/gnu_coreutils/blob/master/src/ls.c

Возможно, это не относится к Windows, но с помощью этих методов можно использовать ряд случаев использования вариантов Unix.

Надеюсь, что это поможет ...

6
ответ дан Homer6 25 August 2018 в 06:28
поделиться
char **getKeys(char *data_dir, char* tablename, int *num_keys)
{
    char** arr = malloc(MAX_RECORDS_PER_TABLE*sizeof(char*));
int i = 0;
for (;i < MAX_RECORDS_PER_TABLE; i++)
    arr[i] = malloc( (MAX_KEY_LEN+1) * sizeof(char) );  


char *buf = (char *)malloc( (MAX_KEY_LEN+1)*sizeof(char) );
snprintf(buf, MAX_KEY_LEN+1, "%s/%s", data_dir, tablename);

DIR* tableDir = opendir(buf);
struct dirent* getInfo;

readdir(tableDir); // ignore '.'
readdir(tableDir); // ignore '..'

i = 0;
while(1)
{


    getInfo = readdir(tableDir);
    if (getInfo == 0)
        break;
    strcpy(arr[i++], getInfo->d_name);
}
*(num_keys) = i;
return arr;
}
4
ответ дан JasonYen2205 25 August 2018 в 06:28
поделиться

Проверьте этот класс, который использует win32 api. Просто создайте экземпляр, предоставив foldername, из которого вы хотите перечислить, затем вызовите метод getNextFile, чтобы получить следующий filename из каталога. Я думаю, что ему нужны windows.h и stdio.h.

class FileGetter{
    WIN32_FIND_DATAA found; 
    HANDLE hfind;
    char folderstar[255];       
    int chk;

public:
    FileGetter(char* folder){       
        sprintf(folderstar,"%s\\*.*",folder);
        hfind = FindFirstFileA(folderstar,&found);
        //skip .
        FindNextFileA(hfind,&found);        
    }

    int getNextFile(char* fname){
        //skips .. when called for the first time
        chk=FindNextFileA(hfind,&found);
        if (chk)
            strcpy(fname, found.cFileName);     
        return chk;
    }

};
8
ответ дан mbinette 25 August 2018 в 06:28
поделиться

Почему бы не использовать glob()?

#include <glob.h>

glob_t glob_result;
glob("/your_directory/*",GLOB_TILDE,NULL,&glob_result);
for(unsigned int i=0; i<glob_result.gl_pathc; ++i){
  cout << glob_result.gl_pathv[i] << endl;
}
17
ответ дан Meekohi 25 August 2018 в 06:28
поделиться

C ++ 17 теперь имеет std::filesystem::directory_iterator , который может использоваться как

#include <string>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    std::string path = "/path/to/directory";
    for (const auto & p : fs::directory_iterator(path))
        std::cout << p << std::endl; // "p" is the directory entry. Get the path with "p.path()".
}

. Кроме того, std::filesystem::recursive_directory_iterator может выполнять итерацию в подкаталогах.

180
ответ дан Roi Danton 25 August 2018 в 06:28
поделиться

Я думаю, ниже фрагмента можно использовать список всех файлов.

#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>

static void list_dir(const char *path)
{
    struct dirent *entry;
    DIR *dir = opendir(path);
    if (dir == NULL) {
        return;
    }

    while ((entry = readdir(dir)) != NULL) {
        printf("%s\n",entry->d_name);
    }

    closedir(dir);
}

Ниже приведена структура struct dirent

struct dirent {
    ino_t d_ino; /* inode number */
    off_t d_off; /* offset to the next dirent */
    unsigned short d_reclen; /* length of this record */
    unsigned char d_type; /* type of file */
    char d_name[256]; /* filename */
};
14
ответ дан Stargateur 25 August 2018 в 06:28
поделиться

Попробуйте повысить метод x-platform

http://www.boost.org/doc/libs/1_38_0/libs/filesystem/doc/index.htm

или просто использовать файлы вашего конкретного файла.

10
ответ дан Tim 25 August 2018 в 06:28
поделиться

Поскольку файлы и вспомогательные каталоги каталога обычно хранятся в древовидной структуре, интуитивно понятный способ - использовать алгоритм DFS для рекурсивного прохождения каждого из них. Вот пример в операционной системе Windows, используя основные функции файла в io.h. Вы можете заменить эти функции на другой платформе. Я хочу выразить, что основная идея DFS отлично справляется с этой проблемой.

#include<io.h>
#include<iostream.h>
#include<string>
using namespace std;

void TraverseFilesUsingDFS(const string& folder_path){
   _finddata_t file_info;
   string any_file_pattern = folder_path + "\\*";
   intptr_t handle = _findfirst(any_file_pattern.c_str(),&file_info);
   //If folder_path exsist, using any_file_pattern will find at least two files "." and "..", 
   //of which "." means current dir and ".." means parent dir
   if (handle == -1){
       cerr << "folder path not exist: " << folder_path << endl;
       exit(-1);
   }
   //iteratively check each file or sub_directory in current folder
   do{
       string file_name=file_info.name; //from char array to string
       //check whtether it is a sub direcotry or a file
       if (file_info.attrib & _A_SUBDIR){
            if (file_name != "." && file_name != ".."){
               string sub_folder_path = folder_path + "\\" + file_name;                
               TraverseFilesUsingDFS(sub_folder_path);
               cout << "a sub_folder path: " << sub_folder_path << endl;
            }
       }
       else
            cout << "file name: " << file_name << endl;
    } while (_findnext(handle, &file_info) == 0);
    //
    _findclose(handle);
}
0
ответ дан tkingcer 25 August 2018 в 06:28
поделиться

Ответ Shreevardhan отлично работает. Но если вы хотите использовать его в c ++ 14, просто сделайте изменение namespace fs = experimental::filesystem;

i.e.,

#include <string>
#include <iostream>
#include <filesystem>

using namespace std;
namespace fs = experimental::filesystem;

int main()
{
    string path = "C:\\splits\\";
    for (auto & p : fs::directory_iterator(path))
        cout << p << endl;
    int n;
    cin >> n;
}
1
ответ дан Venkat Vinay 25 August 2018 в 06:28
поделиться

Надеюсь, этот код вам поможет.

#include <windows.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;

string wchar_t2string(const wchar_t *wchar)
{
    string str = "";
    int index = 0;
    while(wchar[index] != 0)
    {
        str += (char)wchar[index];
        ++index;
    }
    return str;
}

wchar_t *string2wchar_t(const string &str)
{
    wchar_t wchar[260];
    int index = 0;
    while(index < str.size())
    {
        wchar[index] = (wchar_t)str[index];
        ++index;
    }
    wchar[index] = 0;
    return wchar;
}

vector<string> listFilesInDirectory(string directoryName)
{
    WIN32_FIND_DATA FindFileData;
    wchar_t * FileName = string2wchar_t(directoryName);
    HANDLE hFind = FindFirstFile(FileName, &FindFileData);

    vector<string> listFileNames;
    listFileNames.push_back(wchar_t2string(FindFileData.cFileName));

    while (FindNextFile(hFind, &FindFileData))
        listFileNames.push_back(wchar_t2string(FindFileData.cFileName));

    return listFileNames;
}

void main()
{
    vector<string> listFiles;
    listFiles = listFilesInDirectory("C:\\*.txt");
    for each (string str in listFiles)
        cout << str << endl;
}
3
ответ дан Yas 25 August 2018 в 06:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: