ifstream

Автор ioann.sys, 04 июля 2015, 08:58:10

« назад - далее »

0 Пользователи и 1 гость просматривают эту тему.

ioann.sys

Доброе утро!
Требуется прочесть файл настроек, и в дальнейшем его парсить.

И тут я встрял... не вижу таких базовых методов, как ifstream::good() или хотя бы ifstream::eof(). Только is_open(). Как жить?
Debian GNU/Linux jessie/sid on notebook ASUS N750JK

vic5710


ioann.sys

Цитата: vic5710 от 04 июля 2015, 09:54:35
все там есть
http://kvodo.ru/urok-10-1-rabota-s-tekstovyimi-faylami-v-c.html

Спасибо конечно, но это я знаю и пытался применить. Базовый клас std::ios изменен и переименован в std::ios_base.

p.s.: C++11;
Debian GNU/Linux jessie/sid on notebook ASUS N750JK

vic5710

#3
тогда я не в курсе. но  как вариант можно применять С-функции - fopen,fread,fwrite,fclose. там все классически

Cообщение объединено 04 июля 2015, 17:36:32

вот еще что-то
http://habrahabr.ru/post/246257/

smallNix

ioann.sys, кто так пишет??? Сначала надо поздороваться. Потом  описать проблему и ОБЯЗАТЕЛЬНО указать техническую сторону вопроса!!! Какой язык программирования, какой компилятор, какая ОС. Мы должны догадаться по твоему первому сообщению? Твой сарказм во втором сообщении не имеет под собой оснований, т.к. ты ничего не указал ранее, спасибо, что сподобился написать, что надо под C++ 11.
Теперь перейдём к самой проблеме: проблемы нет вовсе.
Под Debian 8, g++ 4.9.2  делаем следущее:
1) Создаём файл 1.dat с содержимым:

John Smith 1
John Smith 2
John Smith 3
John Smith 4
John Smith 5
John Smith 6


потом в этом же каталоге создаём файл main.cpp :

#include <iostream>
using std::cout;
using std::cin;
using std::endl;

#include <fstream>
using std::ifstream;
using std::ios;

int main (int argc, char** argv) {
ifstream inner ("1.dat", ios::in);
if (!inner) {
  cout << "Не удалось создать файл!\n";
  return -1;
}
char name [30];
char lastName [30];
int brainPoints = 0;
while (inner >> name >> lastName >> brainPoints) {
  cout << name << " " << lastName << " " <<  brainPoints << endl;
}

return 0;
}


Собираем так:
g++ -c -std=c++11 main.cpp && g++ -o prog main.o && ./prog

Всё работает. Проверено. Тему можно закрыть.  :P
Кто-то же должен что-то делать...

ioann.sys

smallNix, по-порядку...
Цитата: smallNix от 06 июля 2015, 21:30:04кто так пишет???
Я  ;D


Цитата: smallNix от 06 июля 2015, 21:30:04Сначала надо поздороваться.
А что, доброе утро (в первом посте) не считается за приветствие?

Цитата: smallNix от 06 июля 2015, 21:30:04Потом  описать проблему и ОБЯЗАТЕЛЬНО указать техническую сторону вопроса!!! Какой язык программирования, какой компилятор, какая ОС.
ifstream. Я искренне надеялся, что "крестоносцы" сразу поймут)). Какая может быть речь об OS, если пост на форуме debianforum.ru


Цитата: smallNix от 06 июля 2015, 21:30:04вой сарказм во втором сообщении не имеет под собой оснований, т.к. ты ничего не указал ранее, спасибо, что сподобился написать, что надо под C++ 11.
Это был не сарказм.

На счёт кода:

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
    ifstream f("filename"); // для ifstream не обязательно указывать ios_base::in
    if( !f.is_open() )
    {
      clog << "error" << endl;
    }

    string buffer;
    while( getline(f, buffer) )
    {
      // здесь парсинг буффера
    }

f.close();
return 0;
}



smallNix, и тебе спасибо!


p.s.: я сначала держал настройки приложения в глобальной структуре, а теперь "курю" map.
Debian GNU/Linux jessie/sid on notebook ASUS N750JK

smallNix

#6
C++, структура...  ;D Может лучше класс? Хотя можно и структуру если так удобнее. Настройки можно дерхать в любой удобной форме, хоть в хэш таблице.  :) Не знаю какую библиотеку ты используешь (и используешь ли вообще), но в QT, например, есть прекрасный класс (по моему QSettings), это очень удобно, да и про сереализацию посмотри.

Cообщение объединено 07 июля 2015, 01:30:15

Если напишешь класс, потом сможешь его перенести в другие проекты.

Cообщение объединено 07 июля 2015, 01:37:35

Цитировать
if( !f.is_open() )
{
clog << "error" << endl;
}

Зачем так проверять? Моя проверка быстрее. Хотя не настаиваю.
Цитировать
while( getline(f, buffer) )
Мне кажется это имеет смысл только если у тебя сложный парсинг. Если у тебя простые строки, как в моём примере, то данные без усилий попадают в переменные.

Cообщение объединено 07 июля 2015, 15:06:26

Цитировать
Базовый клас std::ios изменен и переименован в std::ios_base
Глянул ради интереса - это не правда:
http://stackoverflow.com/questions/19128054/ios-and-ios-base-class-for-stream-formatting

Ещё замечание:
Цитировать
if( !f.is_open() )
{
clog << "error" << endl;
}
если файл не получилось открыть на чтение (нет файла, права не те и т.д.), то ты попытаешься обратиться к методу неинициализированного объекта - всё развалится )))
Кто-то же должен что-то делать...

ioann.sys

smallNix, решил воспользоваться твоим приложением и "оформить" настройки в виде класса.

Код ("C++/main.cpp") Выделить

#include "global"

int main()
{
    app_settings.show();
    return 0;
}




#ifndef _APP_GLOBAL_
#define _APP_GLOBAL_

// prototype
class _c_app_settings
{
public:
    _c_app_settings(string);
    void show(void);

private:
    map<string, string> data;
    ifstream f;
};



// А здесь его реализация
_c_app_settings::_c_app_settings(string FILENAME_SETTINGS = "settings.ini")
{
    cout << "Конструктор вызван!" <<  endl;
    f.open(FILENAME_SETTINGS.c_str());
    if (!f.is_open())
    {
        // Кстати, на счёт твоего замечания: этот код для краткости. На самом деле, в проекте используются исключения и различные проверки.
        // в общем, к таким критичным "мелочам", попрошу не придераться))
        clog << "error" << endl;
        return; // чтобы всё не развалилось)))
    }

    // начинаем парсить файл и внутренними (приватными) методами загонять настройки в карту data;
    // code here
}


// Показ текущей конфигурации
void _c_app_settings::show_values()
{
    for (map<string, string>::iterator it = data.begin(); it != data.end(); it++)
    {
        cout << it->first << " : " << it->second << endl;
    }

    return;
}

// а теперь  ВНИМАНИЕ!
// создаём глобальный объект
_c_app_settings app_settings1;    // OK
_c_app_settings app_settings2("settings.ini"); // OK
_c_app_settings app_settings3(); NOT OK


С таким раскладом, всё работает. Но есть вызывать пустой конструктор (), то так не работает.
Debian GNU/Linux jessie/sid on notebook ASUS N750JK

smallNix

 Заставил меня вспоминать и копаться  ;D
Ответ на твой вопрос:
http://stackoverflow.com/questions/877523/error-request-for-member-in-which-is-of-non-class-type
И тут
http://stackoverflow.com/questions/16364116/request-for-member-which-is-of-non-class-type
Если кратко - ты всех путаешь: система сборки думает, что ты определяешь функцию app_settings3() возвращающую объект типа _c_app_settings. Для вызова по умолчанию следует использовать
_c_app_settings app_settings1;

Если попробуешь собрать такой файлик:

  1 #include <iostream>
  2 using std::cout;
  3 using std::endl;
  4 #include <cstring>
  5 using std::string;
  6
  7
  8 class class1 {
  9 public:
10  class1 (string fName = "1.dat");
11  void show ();
12 private:
13  string fileName;
14 };
15
16
17 class1::class1 (string fName) {
18  fileName = fName;
19 }
20
21 void class1::show () {
22  cout << "fileName = " << fileName << endl;
23 }
24
25
26
27 int main () {
28  class1 obj1;
29  class1 obj2 ("2.dat");
30 
31  class1 obj3 ();
32 
33  obj1.show ();
34  obj2.show ();
35  obj3 ();
36  cout.flush ();
37  return 0;
38 }


То всё соберётся, но линковщик не сможет найти реализацию функции obj3. Однако, такой трюк с динамической памятью уже проходит. Следующий вариант работает хорошо:

1 #include <iostream>
  2 using std::cout;
  3 using std::endl;
  4 #include <cstring>
  5 using std::string;
  6
  7
  8 class class1 {
  9 public:
10  class1 (string fName = "1.dat");
11  void show ();
12 private:
13  string fileName;
14 };
15
16
17 class1::class1 (string fName) {
18  fileName = fName;
19 }
20
21 void class1::show () {
22  cout << "fileName = " << fileName << endl;
23 }
24
25
26
27 int main () {
28  class1 obj1;
29  class1 obj2 ("2.dat");
30 
31  class1* obj3 = new class1 ();
32 
33  obj1.show ();
34  obj2.show ();
35  obj3->show ();
36  cout.flush ();
37  return 0;
38 }




Теперь пара мелких замечаний:
1) Лично я всегда разделяю интрефйесную часть и реализацию на два файла (.h и .cpp), используя стражи включения.
2) Параметры по умолчанию всегда только в интерфейсной части.

P.S.: Я не придираюсь, а стараюсь помочь: увидел опасное место - сообщил  ;)

Кто-то же должен что-то делать...

ioann.sys

smallNix, опять нужны твои объяснения на следующий вопрос:
Почему я получаю ошибку сегментирования, если пытаюсь объявить глобальную переменную за пределами фунции main?
То есть, есть три файла c_settings.h, c_settings.cpp и main.cpp.


#include <iostream>
#include "c_settings.h"
using namespace std;

c_settings app_settings; // получается ошибка сегментирования

int main()
{
//c_settings app_settings; // а внутри функции - всё отлично.
app_settings.show();
return 0;
}

Debian GNU/Linux jessie/sid on notebook ASUS N750JK