Осторожный вопрос
От: SteeLHeaD  
Дата: 04.02.13 12:03
Оценка: :))) :))
Господа, настало время спрашивать у вас про С++
Проблема такова:
я прочитал книжку, и мне надо за 3 дня перерписать мой красивенький проект с C# на с++ —
потому что он срочно понадобился коллегам, а у них на с++ все

я полдня пробую записать строчку в файл.
Вот мой код:

#pragma once
#include "stdafx.h"
#include "logger.h"
#include <ctime>
#include <fstream>

using namespace std;

void logger::WriteLog(const char* str)
{
    const char* logFile="c:\Temp\Logs\mainlog.log";

    time_t rawtime;
    time ( &rawtime );
    
    struct tm* timeinfo;
    timeinfo = localtime ( &rawtime );


    char* format = "%I:%M:%S";
    char buffer[50];
    strftime(buffer, 50, format, timeinfo);

    string rez = strcat(strcat(strcat( buffer, ": "), str),  "\r\n");

    ofstream myfile;
     
    myfile.open( logFile, ios_base::out | ios::app );
    myfile.write(rez.c_str(), (long int)rez.length()); 
    myfile.flush();
    myfile.close();


ну что я могу сказать?
не пишет, сука, и ошибок не выдает.

Заодно, не научите ли вы меня складывать строки более человеческим способом, чем strcat()?
Вообще, мне очень нравится библиотека boost, и строки там почти нормальные,
но почему то оператор сложения не работает.
Re: Осторожный вопрос
От: rusted Беларусь  
Дата: 04.02.13 12:12
Оценка:
Здравствуйте, SteeLHeaD, Вы писали:

SLH> const char* logFile="c:\Temp\Logs\mainlog.log";


Смотри предупреждения компилятора на эту строку.
Re: Осторожный вопрос
От: LaptevVV Россия  
Дата: 04.02.13 12:17
Оценка: -2
Здравствуйте, SteeLHeaD, Вы писали:

SLH>я полдня пробую записать строчку в файл.

SLH>Вот мой код:

SLH>
SLH>    const char* logFile="c:\Temp\Logs\mainlog.log";
SLH>


SLH>ну что я могу сказать?

SLH>не пишет, сука, и ошибок не выдает.
Символ '\T' — это табуляция.
Пиши путь с нормальной косой — и будет тебе счастье.
SLH>Заодно, не научите ли вы меня складывать строки более человеческим способом, чем strcat()?
SLH>Вообще, мне очень нравится библиотека boost, и строки там почти нормальные,
SLH>но почему то оператор сложения не работает.
Оператор сложения работает для строк из STL. Тип std::string.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Осторожный вопрос
От: peterbes Россия  
Дата: 04.02.13 12:20
Оценка:
Здравствуйте, SteeLHeaD, Вы писали:

Не пишет потому что файл не открывает:
const char* logFile="c:\Temp\Logs\mainlog.log";


вместо:

const char* logFile="c:\\Temp\\Logs\\mainlog.log";


Такие строчки в коде это неисчерпаемый источник ошибок:
string rez = strcat(strcat(strcat( buffer, ": "), str),  "\r\n");
Re: Осторожный вопрос
От: SteeLHeaD  
Дата: 04.02.13 12:35
Оценка:
Большое спасибо всем за ответы!
Даже не ожидал такой положительной реакции!
Пока все заработало.
я за это время просмотрел документацию по boost::filesystem,
но там люди такими вещами как запись строки в файл не заморачиваются
то есть готового примера там нет.
будем искать!
Re[2]: Осторожный вопрос
От: enji  
Дата: 04.02.13 12:57
Оценка:
Здравствуйте, SteeLHeaD, Вы писали:

SLH>я за это время просмотрел документацию по boost::filesystem,

SLH>но там люди такими вещами как запись строки в файл не заморачиваются
Файлсистем — это работа с файловой системой — создание\удаление\итерация и т.д.

SLH>то есть готового примера там нет.

SLH>будем искать!

    const char* logFile="c:\\Temp\\Logs\\mainlog.log";

    time_t rawtime;
    time ( &rawtime );
    
    struct tm* timeinfo;
    timeinfo = localtime ( &rawtime );


    char* format = "%I:%M:%S";
    char buffer[50];
    strftime(buffer, 50, format, timeinfo);

    //string rez = strcat(strcat(strcat( buffer, ": "), str),  "\r\n");
    // этот код не нужен, см ниже
    // но конкатенировать строки как-то так
    // std::string(buffer) + ": " + str + "\r\n"
    // чтобы работал "+" один из аргументов должен быть std::string
    // str + ":" // ок
    // ":" + str // ок
    // buffer + ":" // не ок (складываются указатели)

    ofstream myfile;
     
    myfile.open( logFile, ios_base::out | ios::app );
    myfile << buffer << ": " << str << "\r\n";
    // myfile.flush(); // вызовется из close()
    // myfile.close(); // при выходе за области видимости close вызовется из деструктора


ЗЫ файл хорошо бы где-нить сохранять, а не переоткрывать при каждом вызове logger::WriteLog
Re[2]: Осторожный вопрос
От: Mihas  
Дата: 04.02.13 13:01
Оценка:
Здравствуйте, peterbes, Вы писали:


P>Не пишет потому что файл не открывает:

P>
P>const char* logFile="c:\Temp\Logs\mainlog.log";
P>


P>вместо:


P>
P>const char* logFile="c:\\Temp\\Logs\\mainlog.log";
P>


SteeLHeaD, оно ж и в шарпе также. Куда смотрел?
Re[2]: Осторожный вопрос
От: enji  
Дата: 04.02.13 13:05
Оценка:
Здравствуйте, SteeLHeaD, Вы писали:

и насчет работы с датой\временем возможно стоит посмотреть на boost::date_time. Возможно покажется проще, чем сишные функции
Re[3]: Осторожный вопрос
От: Mr.Delphist  
Дата: 04.02.13 13:05
Оценка:
Здравствуйте, Mihas, Вы писали:

M>SteeLHeaD, оно ж и в шарпе также. Куда смотрел?


В шарпе можно написать @ перед строкой, и тогда никакого экранирования...
Re: Осторожный вопрос
От: MTD https://github.com/mtrempoltsev
Дата: 04.02.13 13:40
Оценка:
Здравствуйте, SteeLHeaD, Вы писали:

SLH>Вот мой код:


Это не C++, а скорее C, вот С++:

#include <ctime>
#include <fstream>
#include <string>

int main()
{
    std::ofstream file("c:\\Temp\\Logs\\mainlog.log");
    if (!file)
    {
        return 1;
    }

    time_t now = time(0);
    file << "Today is: " << ctime(&now);

    std::string s1 = "Hello, ";
    std::string s2 = "world";
    s1 += s2;
    file << s1;

    return 0;
}
Re[3]: Осторожный вопрос
От: Ops Россия  
Дата: 04.02.13 14:38
Оценка:
Здравствуйте, enji, Вы писали:

E>и насчет работы с датой\временем возможно стоит посмотреть на boost::date_time. Возможно покажется проще, чем сишные функции


Но тут такая вот загогулина
Автор: jazzer
Дата: 29.01.13
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re[2]: Осторожный вопрос
От: Abyx Россия  
Дата: 04.02.13 14:59
Оценка: -1
Здравствуйте, LaptevVV, Вы писали:

LVV>Оператор сложения работает для строк из STL. Тип std::string.

это называется "стандартная библиотека", а не "STL".
в STL строк никогда не было.
In Zen We Trust
Re[4]: Осторожный вопрос
От: Abyx Россия  
Дата: 04.02.13 15:02
Оценка: +1
Здравствуйте, Mr.Delphist, Вы писали:

MD>Здравствуйте, Mihas, Вы писали:


M>>SteeLHeaD, оно ж и в шарпе также. Куда смотрел?


MD>В шарпе можно написать @ перед строкой, и тогда никакого экранирования...


а в С++ можно написать R"(...)", ну и что?
In Zen We Trust
Re: Осторожный вопрос
От: VladFein США  
Дата: 04.02.13 15:10
Оценка: -2
Здравствуйте, SteeLHeaD, Вы писали:

SLH>...и мне надо за 3 дня перерписать мой красивенький проект с C# на с++ —


А в C# у Вас тоже нет проверок на успех/провал файловых операций?
Re[3]: Осторожный вопрос
От: LaptevVV Россия  
Дата: 04.02.13 17:57
Оценка: +2 -1
Здравствуйте, Abyx, Вы писали:

A>Здравствуйте, LaptevVV, Вы писали:


LVV>>Оператор сложения работает для строк из STL. Тип std::string.

A>это называется "стандартная библиотека", а не "STL".
A>в STL строк никогда не было.
Почему?
Standart Template Library — это стандартная библиотека С++.
Джоссатис написал... Член комитета как раз по этому вопросу...
Глава 11 его книжки.
Или вы различаете термины Standart Template Library и стандартная библиотека.
Я предпочитаю не различать.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[4]: Осторожный вопрос
От: Abyx Россия  
Дата: 05.02.13 08:22
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>>>Оператор сложения работает для строк из STL. Тип std::string.

A>>это называется "стандартная библиотека", а не "STL".
A>>в STL строк никогда не было.
LVV>Почему?
LVV>Standart Template Library — это стандартная библиотека С++.
никакой STL в действующем стандарте нет.
есть Strings library и куча других либ. все они вместе называются standart library

LVV>Джоссатис написал... Член комитета как раз по этому вопросу...

LVV>Глава 11 его книжки.
какой книжки, какое издание?

LVV>Или вы различаете термины Standart Template Library и стандартная библиотека.

да. STL была разработана Степановым для ранних версий С++, в ней никаких строк не было.
потом, в С++98 из нее сделали Algorithms library, часть Numerics library и т.п.

LVV>Я предпочитаю не различать.

я предпочитаю использовать корректные термины.
In Zen We Trust
Re[2]: Осторожный вопрос
От: Abyx Россия  
Дата: 05.02.13 08:23
Оценка: -1
Здравствуйте, VladFein, Вы писали:

VF>А в C# у Вас тоже нет проверок на успех/провал файловых операций?


проверок чего? кода возврата? нету.
In Zen We Trust
Re[2]: Осторожный вопрос
От: LaptevVV Россия  
Дата: 05.02.13 09:03
Оценка:
Здравствуйте, SteeLHeaD, Вы писали:

SLH>Большое спасибо всем за ответы!

SLH>Даже не ожидал такой положительной реакции!
SLH>Пока все заработало.
SLH>я за это время просмотрел документацию по boost::filesystem,
SLH>но там люди такими вещами как запись строки в файл не заморачиваются
SLH>то есть готового примера там нет.
SLH>будем искать!
Элементарные примеры в моей книжке написаны. И здесь на форуме я постил — поищи.

По традиции в Windows разделителем является символ обратной косой черты (\). В программе на С++ этот символ необходимо писать дважды (\\), так он является специальным символом. Однако допускается использовать и обычную косую черту (/). Разделитель должен отделять диск от имени каталога. Примеры имен:
"question.txt"
"c:\\test\\question.doc"
"a:/number.bin"

И далее:

Пример обработки текстовых файлов

В качестве примера обработки текстовых файлов напишем программу, которая реализует наиболее часто используемую функцию препроцессора — подключение файлов с помощью оператора #include. Ограничим синтаксис оператора:
 оператор начинается с первой позиции строки;
 подключаемый файл всегда задается в формате «имя_файла»;
 имя файла отделяется от оператора #include только одним пробелом.

Таким образом, непосредственно имя файла начинается в операторе всегда с 11-й позиции и продолжается до символа-кавычки. Подключаемый файл тоже может содержать операторы #include. Ограничение вложенности, очевидно, задается глобальной константой FOPEN_MAX, определяющей максимальное количество одновременно открытых файлов и определенной в заголовке <stdio.h>.

Итак, в результате получаем:
#include "имя_файла"
При подключении этот оператор записывается в результирующий файл как комментарий:
//----------#include имя_файла----------

После этой строки в результирующий файл записывается содержимое указанного файла. Если подключаемый файл не был открыт, то в результирующий файл записывается строка-комментарий:
//----------#include имя_файла -- Error! -- File not open!

Подключаемые файлы могут, вообще говоря, располагаться в различных каталогах, но мы для проверки работы программы соберем их все в нашем каталоге TextFiles. Файл, который надо обрабатывать первым, задается в командной строке. Если имя задано неверно, то программа завершает работу. Результирующий файл с именем result.files размещается в том же каталоге TextFiles. Текст программы представлен в листинге 14.5.

Листинг 14.5. Обработка оператора #include
string NameFiles(const char *namefile)
{ string path = "c:/textfiles/";
  return path+namefile;
}
bool isInclude(const string line)
{ if (line.substr(0,8) == "#include") return true;
  else                                return false;
}
void includeFile(const char *namefile, ofstream &result)
{    static int countfiles = 0;
    ++countfiles; 
    if (countfiles > FOPEN_MAX)          // файлов больше положенного?
    { cerr << "Too mani files is opened!" << endl;
      abort();
    }
    string line;                         // читаемая строка
    const string tenminus = "----------";
    const string include = "#include ";
    string comment;
    string name = NameFiles(namefile);   // полное имя файла
    ifstream in;                         // очередной входной файл
    in.open(name.c_str());               // открыли
    if(in.is_open())                     // если открылся
    {    getline(in, line);
        while(!in.eof()) 
        { if (isInclude(line))           // если #include
          {   char file[FILENAME_MAX];
              int i = 0;  // извлекаем имя файла из #include
              while(line[i+10]!='"') { file[i]=line[i+10]; i++; }
              file[i] = 0;               // завершающий ноль
              comment = "//"+tenminus+include+file+tenminus;
              result << comment << endl;
              includeFile(file, result); // пошли внутрь
              result <<"//-end------------------------------\n";
          }
          else  result << line << endl;
          getline(in, line);
        }
        in.close();
    }
    else // формируем ошибочный комментарий
    { const string Error = "Error! -- File not open!";
      comment = "//"+tenminus+include+namefile+" -- "+Error+'\n';
      result << comment;
    }
}
int main(int argc, char *argv[])
{    ofstream result ("c:/textfiles/result.files");
    if(!result.is_open())                // ошибка при открытии
    {    cerr << "Error result file!" << endl; 
        return 1;                
    }
    includeFile(argv[1], result);
    result.close();
    return 0;
}


Главная программа просто открывает результирующий файл и вызывает рекурсивную функцию обработки, передавая ей в качестве параметра имя файла из командной строки и поток-результат. Ошибки практически не обрабатываются, чтобы не отвлекаться от основной задачи — обработки файлов.
Основную работу выполняет рекурсивная функция includeFile(), аргументом которой является имя обрабатываемого файла и поток-результат. Функция в начале считает количество открытых файлов — можно запрограммировать здесь более серьезную обработку ошибки (например, генерировать исключение). Если все в порядке, то формируется полное имя файла — работает вспомогательная функция NameFiles(). Далее файл открывается, и в цикле читаются строки файла. Если прочитана обычная строка, то она просто выводится в результирующий файл. Если же строка содержит оператор #include (что определяет простая функция-предикат isInclude()), то формируется и выводится строка-комментарий о включаемом файле, и выполняется рекурсивный вызов. По окончании файла выводится дополнительная строка минусов со словом «end». Таким образом, включенный файл оказывается обрамленным двумя строками-комментариями. Если же при открытии файла возникли проблемы, то формируется строка-комментарий с ошибкой, и функция завершает обработку текущего файла.
Создадим в каталоге TextFiles три небольших текстовых файла a.txt, b.txt и d.txt:
 файл a.txt:

 aaaaaaaaaaaaaaa
    #include "b.txt"
    aaaaaaaaaaaaaaa


 файл b.txt:

 bbbbbbbbbbbbbbbbbb
    #include "d.txt"
    bbbbbbbbbbbbbbbbbb
    #include "dd.txt"
    bbbbbbbbbbbbbbbbbb


 файл d.txt:

 dddddddddddddddddd
    dddddddddddddddddd


Файл a.txt подключает файл b.txt, который, в свою очередь, подключает файл d.txt и ошибочный файл dd.txt. Результат работы нашей программы получается следующий:

aaaaaaaaaaaaaaa
//----------#include b.txt----------
bbbbbbbbbbbbbbbbbb
//----------#include d.txt----------
dddddddddddddddddd
dddddddddddddddddd
//-end-------------------------------
bbbbbbbbbbbbbbbbbb
//----------#include dd.txt----------
//----------#include dd.txt -- Error! -- File not open!
//-end-------------------------------
bbbbbbbbbbbbbbbbbb
//-end-------------------------------
aaaaaaaaaaaaaaa


Как видим, вложенные файлы обрабатываются совершенно правильно.
Собственно, если бы не нужно было формировать комментарий вокруг вложенного файла, функция includeFile() была бы значительно короче (листинг 14.6).

Листинг 14.6. Функиця includeFile()
void includeFile(const char *namefile, ofstream &result)
{    static int countfiles = 0;
    ++countfiles;            // проверяем countfiles > FOPEN_MAX
    if (countfiles > FOPEN_MAX) 
    { cerr << "Too mani files is opened!" << endl; abort();    }
    string line;
    string name = NameFiles(namefile);
    ifstream in;
    in.open(name.c_str());
    if(in.is_open()) 
    {    getline(in, line);
        while(!in.eof())
        { if (isInclude(line)) includeFile(file, result);
          else                     result << line << endl;
          getline(in, line);
        }
        in.close();
    }
    else result << "Error! -- File not open!" << endl;
}

Этот вариант функции вполне можно использовать в «настоящем» препроцессоре.

Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[5]: Осторожный вопрос
От: Mr.Delphist  
Дата: 05.02.13 09:28
Оценка:
Здравствуйте, Abyx, Вы писали:

A>Здравствуйте, Mr.Delphist, Вы писали:


MD>>Здравствуйте, Mihas, Вы писали:


M>>>SteeLHeaD, оно ж и в шарпе также. Куда смотрел?


MD>>В шарпе можно написать @ перед строкой, и тогда никакого экранирования...


A>а в С++ можно написать R"(...)", ну и что?


А вот с этого места — можно поподробнее? T-макрос знаю, а вот R — никогда не встречался.
Re[6]: Осторожный вопрос
От: Abyx Россия  
Дата: 05.02.13 09:31
Оценка: 6 (1)
Здравствуйте, Mr.Delphist, Вы писали:

A>>а в С++ можно написать R"(...)", ну и что?


MD>А вот с этого места — можно поподробнее? T-макрос знаю, а вот R — никогда не встречался.


это raw string literal.
In Zen We Trust
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.