Вопрос был:
Как вернуть ответ от асинхронного вызова?
, который может быть интерпретирован как:
Как сделать синхронный асинхронный код синхронным?
Решение будет состоять в том, чтобы избежать обратных вызовов и использовать комбинацию 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")
В небольших и простых задачах я не использую 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.
Вот очень простой код в 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
System call it!
system( "dir /b /s /a-d * > file_names.txt" );
Затем просто прочитайте файл.
EDIT: Этот ответ следует считать взломом, но он действительно работает (хотя и на платформе конкретный способ), если у вас нет доступа к более элегантным решениям.
Это сработало для меня. Он записывает файл с именами (без пути) всех файлов. Затем он считывает этот 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;
}
}
Я рекомендую использовать 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("./*");
Для решения только 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);
Некоторые преимущества перед другими опциями:
readdir_r
, где доступно, что означает, что он (обычно) threadsafe UNICODE
макросы К сожалению, стандарт C ++ не определяет стандартный способ работы с файлами и папками таким образом.
Поскольку нет кросс-платформенного способа, лучшим кросс-платформенным способом является использование библиотеки, такой как модуль boost fileystem .
Метод повышения перекрестной платформы :
Следующая функция, заданная пути к каталогу и имени файла, рекурсивно ищет каталог и его подкаталоги для имени файла, возвращает bool, и в случае успеха путь к файл, который был найден.
blockquote>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 '', это:
blockquote>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.
blockquote>#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.
вы можете получить все прямые файлы в корневом каталоге, используя 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;
}
Это работает для меня. Извините, если я не могу вспомнить источник. Вероятно, это с 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/");
}
Эта реализация реализует вашу цель, динамически заполняя массив строк содержимым указанного каталога.
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;
}
Одной функции достаточно, вам не нужно использовать стороннюю библиотеку (для 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-файлы (т. е. определенного типа) в этом каталоге.
GNU Manual FTW
Кроме того, иногда бывает хорошо перейти прямо к источнику (каламбур). Вы можете многому научиться, глядя на внутренности некоторых из наиболее распространенных команд в Linux. Я установил простое зеркало ядра ядра GNU на github (для чтения).
https://github.com/homer6/gnu_coreutils/blob/master/src/ls.c
Возможно, это не относится к Windows, но с помощью этих методов можно использовать ряд случаев использования вариантов Unix.
Надеюсь, что это поможет ...
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;
}
Проверьте этот класс, который использует 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;
}
};
Почему бы не использовать 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;
}
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
может выполнять итерацию в подкаталогах.
Я думаю, ниже фрагмента можно использовать список всех файлов.
#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 */
};
Попробуйте повысить метод x-platform
http://www.boost.org/doc/libs/1_38_0/libs/filesystem/doc/index.htm
или просто использовать файлы вашего конкретного файла.
Поскольку файлы и вспомогательные каталоги каталога обычно хранятся в древовидной структуре, интуитивно понятный способ - использовать алгоритм 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);
}
Ответ 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;
}
Надеюсь, этот код вам поможет.
#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;
}