выводит список файлов из popen в ifstream.open - PullRequest
2 голосов
/ 07 марта 2012

В основном мне нужно открыть и прочитать список файлов, которые я получаю от другой команды. Для каждой строки вывода popen открыть файл usen ifstream.open

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

вот код:

#include <iostream>
#include <sqlite3.h>
#include <stdio.h>
#include <fstream>

using namespace std;


int main () {

    ifstream singlefile;
    FILE *filelist;
    char filename[512];
    string progline;

    if(!(filelist = popen("find `pwd` -name \"*.js\"", "r"))){
        return 1;
    }

    while( fgets(filename, sizeof(filename), filelist)!=NULL)
    {
        cout << filename;
        singlefile.open(filename, ifstream::in);
        while ( singlefile.good() )
        {
            getline (singlefile,progline);
            cout << progline << endl;
        }

        singlefile.close();
    }

    pclose(filelist);

  return 0;

}

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

Спасибо

1 Ответ

2 голосов
/ 07 марта 2012

fgets сохраняет завершающий символ новой строки, что приводит к имени файла несуществующего файла. Также состояние потока обновляется только после чтения. Если я заменю тело while на следующий код, у меня это сработает:

  cout << filename;
  size_t len = strlen(filename);
  // chop off trailing newline
  if (len > 1 && filename[len - 1] == '\n') filename[len - 1] = 0;
  singlefile.open(filename, ifstream::in);
  while ( getline(singlefile, progline) )
    {
      cout << progline << endl;
    }

  singlefile.close();

Если вы действительно хотите перебирать список файлов, я бы использовал Boost.Filesystem , который имеет приятный интерфейс C ++, работает для всех имен файлов (даже для тех, у которых есть символы новой строки) и независимый от платформы.

Если это на самом деле только пример, а ваша фактическая команда не find, есть еще место для упрощения. Вот предложение, которое использует Boost.Iostreams , чтобы избавиться от большинства вызовов функций C (было бы здорово иметь чтение источника устройства из стандартного вывода процесса, но Boost.Iostreams этого не хватает):

#include <cstdio>
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <string>

#include <stdio.h>

#include <boost/noncopyable.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>

using namespace std;
namespace io = boost::iostreams;

class Popen: private boost::noncopyable {
public:
  explicit Popen(const char* command):
    m_stream(popen(command, "r")) {
    if (!m_stream) throw runtime_error("popen failed");
  }

  ~Popen() {
    pclose(m_stream);
  }

  FILE* stream() const {
    return m_stream;
  }

private:
  FILE* m_stream;
};


int main() {
  Popen pipe_wrapper("find `pwd` -name \"*.cpp\"");
  io::file_descriptor_source pipe_device(fileno(pipe_wrapper.stream()), io::never_close_handle);
  io::stream<io::file_descriptor_source> pipe_stream(pipe_device, 0x1000, 0x1000);
  string filename;
  while (getline(pipe_stream, filename)) {
    cout << filename << endl;
    ifstream file_stream(filename.c_str(), ifstream::in);
    string progline;
    while (getline(file_stream, progline)) {
      cout << progline << endl;
    }
  }
}
...