Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Работа с текстовым фалом в формате csv и xml


Автор: Moby 30.8.2010, 12:57
Задача: Есть два файла один текстовой и один формата xml. В каждом хранится много информации в основном численной. Что мне с ними делать надо будет не столь важно, а важно получить внутреннее представление этих фалов, ну там в массив все загнать или еще что нибудь.

Для начала вот как выглядит текстовой файл в формате csv.

xx,xxxxxxxxxxxxxxx;xx,xxxxxxxxxxxxxxx;dd.mm.yyyy hh:mm:ss

где x = 0...9, то есть любое число, а дальше это дата и время.

И само собой таких записей много, то есть

xx,xxxxxxxxxxxxxxx;xx,xxxxxxxxxxxxxxx;dd.mm.yyyy hh:mm:ss
xx,xxxxxxxxxxxxxxx;xx,xxxxxxxxxxxxxxx;dd.mm.yyyy hh:mm:ss
.
.
.
.
.
.
.
xx,xxxxxxxxxxxxxxx;xx,xxxxxxxxxxxxxxx;dd.mm.yyyy hh:mm:ss


Вопрос: Как мне лучше представить эти данные? Создать 4х мерный массив? Или есть более удобное представление? И как бы то ни было ведь нужно будет использовать файловый ввод-вывод, желательно С++ а не С. И что именно использовать.

Я не прошу Вас о полном ответе, мне хватит и общих наставлений. Ну может быть есть удобные структуры хранения таких данных в STL и может быть очень удобная функция типа fseek() что бы легко отделить дату от первых двух значений.

Заранее спасибо. 

Автор: kosmonaFFFt 30.8.2010, 13:04
http://mac.softpedia.com/get/Development/Libraries/libcsv.shtml

Автор: Moby 30.8.2010, 15:08
Спасибо. Но для меня, учитывая сроки, тяжко разобраться как это использовать, да и хотелось бы самому.

Как мне используя fstream раскидать по массиву вот такой текстовый файл
10;20;30
40;50;60 


что бы i[0][0] = 10, i[1][0] = 20.....

ifstream in;
in.open("test.txt");

а дальше что делать? 


Автор: djamshud 30.8.2010, 15:24
Вам не кажется, что это руками пишется за две минуты?

Автор: Moby 30.8.2010, 15:38
Смотря какие руки. smile
Я никогда не работал с вводом\выводом текстовых файлов и никогда не использовал fstream. Конечно сейчас я читаю, смотрю примеры и постепенно учусь, но если бы кто-то написал хоть что нибудь, то хуже бы не стало. Я же не спрашиваю а как сделать так, что бы консоль не закрывалась. smile

Автор: bsa 30.8.2010, 17:53
Moby, тебе нужна структура, состоящая из 3-х полей:
Код
struct MyData
{
   long double x;
   long double y;
   time_t date;
   MyData(); //создает пустую структуру
   explicit MyData(const std::string &line); //парсит строку
};

std::vector<MyData> array;

Автор: jonie 30.8.2010, 18:28
bsa, тебе не кажется что использование констроров тут излишне ? Мне кажется что стоит использовать operator<< , нежели конструкторы .. да и нагляднее имхо.
Хотя с другой стороны имея implicit конструктор из строки в данные можно использовать :
Код

vector<RowData> rows;
std::copy(std::istream_iterator<string>(input), std::istream_iterator<string>(), std::back_inserter(rows));

Автор: ИванМ 30.8.2010, 20:58
Цитата(Moby @  30.8.2010,  15:08 Найти цитируемый пост)
Как мне используя fstream раскидать по массиву вот такой текстовый файл
10;20;30
40;50;60 
что бы i[0][0] = 10, i[1][0] = 20.....

Если только из трех столбцов состоит файл и i - си-строка, то можно два раза вызвать getline с символом-разделителем ';' и один раз с '\n'. Типа такого:
Код

for(size_t j=0;!in.eof();j++)
{
in.getline(i[0][j], максимальная_длина, ';');
in.getline(i[1][j], максимальная_длина, ';');
in.getline(i[2][j], максимальная_длина, '\n');
} 

Если i - int:
Код

for(size_t j=0;!in.eof();j++)
for(size_t k=0;k<3;k++)
{
    in>>i[k][j];
    in.get();
}

Автор: Moby 30.8.2010, 22:54
Спасибо за ответы. Только прочел их, а до этого все таки сидел и сам пытался разобраться. Многое сделано тупо и в лоб. Посмотрите и прокомментируйте, что мне переписать "по человечески".


Использовал два потока. Один что бы посчитать кол-во строк. Зачем? Потому что после вот такого условия
Код

 while(!in1.eof())
    {
        rows++;
        getline(in1, str);
    }
 не знаю как вернуться к первой строке. smile

Но самое главное это то, что в текстовом файле лежит значение 55,6685371398926 а в массив попадает урезанная 55.6685. То есть 4-е знака после запятой. Как тут быть? 
Так же прошу заметить тупой способ борьбы с запятой. Значения в тексте используют разделитель не точку, а запятую. Я сперва беру все значение как стринг и разбиваю уже его на до запятой и после и складываю со знаком точка и только потом перевожу в флоат. Весьма тупо, не правда ли. smile
А вот код.

Код


#include "stdafx.h"
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{


    string str1,str2,str;
    fstream in, in1;
    int pos, pos2, rows = 0;
    float f;
    stringstream ss;
    cout << "Please, enter full path to file" << endl;

    in.open("test.txt");
    in1.open("test.txt");
    
    while(!in1.eof())
    {
        rows++;
        getline(in1, str);
    }
    str.clear();
    in1.close();
    rows-=1;
    
    float** matrix = new float*[rows];
    for (int i = 0; i <= rows; ++i)
        matrix[i] = new float[3];

    for (int i = 0; i < rows; ++i)
    {
        getline(in, str1);
        cout << str1 << endl;

        for(int j = 0; j < 2; j++)
        {
            pos = str1.find(";");
            
            str2.assign(str1, 0, pos);
            pos2 = str2.find(",");
            str.assign(str2, pos2+1, str2.size());
            str2.assign(str2,0,pos2);
            str2=str2+"."+str;
            ss << str2;
            ss >> f;
            ss.clear();
            matrix[i][j] = f;
            str1.assign(str1, pos+1, str1.size());
        }
    }
    cout << endl;

    for(int i = 0; i < rows; i++)
    {
        for(int j = 0; j <2; j++)
        {
            cout << matrix[i][j]<< ";";
        }
        cout << endl;
    }
    

    system("pause");
    return 0;
}


 

Автор: ИванМ 30.8.2010, 23:11
Цитата(Moby @  30.8.2010,  22:54 Найти цитируемый пост)
Использовал два потока. Один что бы посчитать кол-во строк. Зачем? Потому что после вот такого условия
 while(!in1.eof())
    {
        rows++;
        getline(in1, str);
    }
 не знаю как вернуться к первой строке. smile

Вообще ничего не понял. Причем тут подсчет строк и первая строка и как это связано с потоками. В вашем коде ни одного второго потока не нашел.

Цитата(Moby @  30.8.2010,  22:54 Найти цитируемый пост)
Но самое главное это то, что в текстовом файле лежит значение 55,6685371398926 а в массив попадает урезанная 55.6685. То есть 4-е знака после запятой. Как тут быть? 

Хранить в double и при выводе использовать нужные флаги. Пример:
Код

double d=55.6685371398926;
cout<<fixed<<setprecision(13)<<d<<endl;


Цитата(Moby @  30.8.2010,  22:54 Найти цитируемый пост)
Так же прошу заметить тупой способ борьбы с запятой. Значения в тексте используют разделитель не точку, а запятую. Я сперва беру все значение как стринг и разбиваю уже его на до запятой и после и складываю со знаком точка и только потом перевожу в флоат. Весьма тупо, не правда ли. 

Для таких целей существует локаль ( setlocale(...) ).

Цитата(Moby @  30.8.2010,  22:54 Найти цитируемый пост)
Посмотрите и прокомментируйте, что мне переписать "по человечески".

Чтобы было по-человечески придется переписать весь код. Почитайте, что вам рекомендовали про классы (хотя для такого случая можно и без них). Забудьте про динамические массивы, используйте контейнеры. Тогда вам вообще не придется подсчитывать число строк.

Автор: jonie 31.8.2010, 08:05
Код

using namespace std;

class RowData
{
    long double x;
    long double y;
    string date;

    //RowData& operator=(const RowData str);
public:
    friend istream& operator>>(istream& is, RowData& rhs);
    RowData()
    {
    }

    RowData(string s)
    {
        istringstream is(s);
        is>>*this;
    }
};

istream& operator>>(istream& is, RowData& rhs)
{
    is>>rhs.x;
    is.get();
    is>>rhs.y;
    is.get();
//.... парсинг даты...
    return is;
}


//где-то в main
    std::locale loc ("German_Germany");
    std::locale::global(loc);  //плохой код)

    ifstream input("C:\\test.data", fstream::in);
    
    vector<RowData> rows;
    std::copy(std::istream_iterator<string>(input), std::istream_iterator<string>(), std::back_inserter(rows));

Автор: Moby 31.8.2010, 13:51
Цитата(ИванМ @ 30.8.2010,  23:11)
Цитата(Moby @  30.8.2010,  22:54 Найти цитируемый пост)
Использовал два потока. Один что бы посчитать кол-во строк. Зачем? Потому что после вот такого условия
 while(!in1.eof())
    {
        rows++;
        getline(in1, str);
    }
 не знаю как вернуться к первой строке. smile

Вообще ничего не понял. Причем тут подсчет строк и первая строка и как это связано с потоками. В вашем коде ни одного второго потока не нашел.

Я неправильно обозвал это, я имел ввиду что создал два  fstream .

Но я так и не понял как можно после подсчета строк таким образом вернуться на первую?

jonie, спасибо. Выглядит очень просто, кое что непонятно, но буду разбираться.

Автор: ИванМ 31.8.2010, 13:59
Цитата(Moby @  31.8.2010,  13:51 Найти цитируемый пост)
Но я так и не понял как можно после подсчета строк таким образом вернуться на первую?

Никак. Просто не нужно делать подсчет строк.

jonie, я бы использовал list, а не vector, с остальным согласен.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)