Пятница, 29 Марта 2024, 01:20

Приветствую Вас Гость

[ Новые сообщения · Игроделы · Правила · Поиск ]
  • Страница 1 из 1
  • 1
Форум игроделов » Программирование » C/C++ » Работа с файлами (Неправильно возвращает строку)
Работа с файлами
StealthДата: Среда, 26 Декабря 2012, 23:17 | Сообщение # 1
был не раз
Сейчас нет на сайте
Вообщем при чтении с файла нужного значения получается такая штука


Вот код функции
Код
#include <iostream>
using namespace std;

//-----DEBUG---------------------

char* cc(char* ch1, char* ch2)
{
      char* nc = new char[std::strlen(ch1) + std::strlen(ch2)]();
      strcat(nc,ch1);
      strcat(nc,ch2);
      return nc;
};

char* Read(char* file,char* section,char* key)
{
      char* r;
      FILE* f = fopen(file,"rt");
      if(!f)
      {
       cout << "Can't Open file: " << file;
       return "";
      }
      char* newsection = cc("[",cc(section,"]"));
      newsection = cc(newsection,"\n");
      while(!feof(f))
      {
       char* tmp = new char();
       fgets(tmp,100,f);
       //Проверка секции
       if(strcmp(tmp,newsection) == 0)
       {
        char ch[100];
        fgets(ch,100,f);
        char* nk = new char();
        //Поиск нужной строки (до конца файла или до новой секции)
        while((ch[0] != '[') && (ch[0] != EOF))
        {
         char* ct = ch;
         for(int i = 0;i<strlen(ct);i++)
         {
          if(ct[i] == '=')
          {
           nk = strncpy(nk,ct,i);
           nk[i] = '\0';
           //Проверка ключа
           if(strcmp(nk,key) == 0)
           {
            r = strstr(ct,"=")+1;
            cc("\0",r);
            fclose(f);
            cout << "Settings: " << r;
            return r;
           }
          }
         }
         fgets(ch,100,f);
        }
        cout << "Can't find key in file: " << file;
        return "";
       }
      }
      cout << "Can't find section in file: " << file;
      fclose(f);
      return "";
};

//-------------------------------

void main()
{
      cout << Read("Some.txt","game","d");
      cin.get();
};


Some.txt выглядит вот так
Код
[game]
sdaf=sdflk
sdflk=dsf
d=sdkfj


У кого-нибудь есть мысли в чем дело?

IDE - MS Visual Studio 2012 Desktop


Сообщение отредактировал Stealth - Четверг, 27 Декабря 2012, 10:55
tourniquetДата: Четверг, 27 Декабря 2012, 02:20 | Сообщение # 2
частый гость
Сейчас нет на сайте
Может проблема с кодировкой фаила? Текст на русском? А если текст в фаиле латинскими буквами тоже такая проблема?
StealthДата: Четверг, 27 Декабря 2012, 10:50 | Сообщение # 3
был не раз
Сейчас нет на сайте
Пробовал менять кодировку файла: он его вообще отказывается читать. По русски он не читает.
Вся проблема в том, что с файлом он работает правильно (см. на скрине первую строчку), а строку возвращает абра-кадаброй.
AlexeyBondДата: Четверг, 27 Декабря 2012, 11:44 | Сообщение # 4
был не раз
Сейчас нет на сайте
Похоже, дело в том, что в конце выводимой строки отсутствует завершающий символ ('\0').
В чём точно причина, сказать не могу, но вот ошибки, которые сразу бросаются в глаза:

Код
char* nc = new char[std::strlen(ch1) + std::strlen(ch2)]();

Здесь не выделяется память под тот самый '\0'.

Код
char* tmp = new char();
fgets(tmp,100,f);

Здесь в массив из одного символа записывается сразу 100 (удивительно, что программа вообще работает).

Код
cc("\0",r);

Этот вызов вообще ничего не делает.

И вообще: память используется очень нерационально, как и время( нужно заново разбирать файл чтобы найти каждое следующее значение ).
StealthДата: Четверг, 27 Декабря 2012, 15:18 | Сообщение # 5
был не раз
Сейчас нет на сайте
Ну меня не учили как правильно использовать память, поэтому, уж извините что есть... учусь.

Код
cc("\0",r);

На счет этой строчки - это я дебажил (уже от безысходности).

переписал функцию сс. Не знаю правильно или нет.
Код
char* cc(char* ch1, char* ch2)
{
  char* nc = new char[std::strlen(ch1) + std::strlen(ch2) + 1]();
  strcat(nc,ch1);
  strcat(nc,ch2);
  strcat(nc,"\0");
  return nc;
};


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

Странно то, что на VS2010E все работало...
TikaraДата: Четверг, 27 Декабря 2012, 16:09 | Сообщение # 6
частый гость
Сейчас нет на сайте
Stealth, на ваш код смотреть очень больно, скажу я вам.

Код
#include <iostream>       
#include <string.h>
using namespace std;       

//-----DEBUG---------------------       

char* Read(char* file,char* section,char* key)       
{      
            FILE* f = fopen(file,"rt");       
            if(!f)       
            {       
             cout << "Can't Open file: " << file;       
             return "";       
            }       
                  
         char* tmp = new char[100];       

         while(fgets(tmp,100,f))       
         {       
          //Проверка секции       
          if(tmp[0]=='[' && strstr(tmp,section))  // из-за strstr секции, например, Sound и SoundSettings будут считаться одинаковыми, как их различить, думаю, сами допишите     
          {       
           //Поиск нужной строки (до конца файла или до новой секции)       
           while((fgets(tmp,100,f)) && (tmp[0] != '['))       
           {
            int size = strlen(tmp);
            for(int i = 0;i<size;i++)       
            {
             if(!strcmp(strtok(tmp,"="),key))       
             {       
             return strtok(NULL,"");
             }       
            }       
           }       
           cout << "Can't find key in file: " << file << '\n';       
           fclose(f);
           return "";       
          }       
         }       
         cout << "Can't find section in file: " << file << '\n';       
         fclose(f);       
         return "";       
}

//-------------------------------       

void main()       
{       
            cout << Read("Some.txt","game","d") << '\n';       
         cin.get();
}


Вот вам мой вариант. Согласитесь можно же лучше, если захотеть?

И кстати да, как выразился Уважаемый AlexeyBond, чтобы достать каждое новое значение требуется заного производить поиск в файле.

Я бы вам посоветовал прочитать весь файл и записать в память. А дальше выполнять поиск в памяти. А если секций/ключей слишком много, то можно и хеширование для поиска использовать. И тогда дело пойдёт на лад biggrin

Удачи!


Сообщение отредактировал Tikara - Четверг, 27 Декабря 2012, 16:52
StealthДата: Четверг, 27 Декабря 2012, 18:27 | Сообщение # 7
был не раз
Сейчас нет на сайте
Tikara, спасибо, все работает.

Цитата
Stealth, на ваш код смотреть очень больно, скажу я вам.

А что вы хотели от студента 2 курса колледжа....нормально кодить нас еще не научили. Приходится все самому допирать.

Цитата
Я бы вам посоветовал прочитать весь файл и записать в память. А дальше выполнять поиск в памяти. А если секций/ключей слишком много, то можно и хеширование для поиска использовать. И тогда дело пойдёт на лад

Можете объяснить по подробнее или хотя бы где про это можно подробнее прочитать.

Теперь похожая задача: нужно записать в файл значение. Как это можно сделать?
TikaraДата: Четверг, 27 Декабря 2012, 19:07 | Сообщение # 8
частый гость
Сейчас нет на сайте
Цитата (Stealth)
Можете объяснить по подробнее или хотя бы где про это можно подробнее прочитать.


Тут всё зависит от задачи. Структура файла заранее известна? Если да, то можно заранее обьявить переменные и инициализировать каждую во время одной разборки файла. Если секции и ключи расположены по разному и могут иметь различные значения, то можно реализовать связный список секций и ключей, а далее выполнять поиск. Только я не знаю для чего это пригодится, только если вы не пишете свою библиотеку конечно.

Про хэшироавние можно в гугле спокойно найти всю информацию.

Цитата (Stealth)
Теперь похожая задача: нужно записать в файл значение. Как это можно сделать?


Вам нужно использовать тот же файл и вы хотите переписать значение какого-то ключа? То тогда всё просто: игра во время запуска инициализирует все переменные настроек из файла. Далее когда пользователь меняет какие-то настройки, соответствующие переменные меняют свои значения. Пользователь "жмякает" на кнопку "сохранить" и в итоге создаётся новый файл, заменяя старый, который сохраняет структуру файла настроек с новыми значениями.


Сообщение отредактировал Tikara - Четверг, 27 Декабря 2012, 19:08
StealthДата: Четверг, 27 Декабря 2012, 21:35 | Сообщение # 9
был не раз
Сейчас нет на сайте
Tikara, насколько я понял, что перезаписать файл нужно сохранить все строчки, потом заменить нужные, и все это записать. Но вот только построчно у меня сохранить не получается: сохраняется только последняя строка, причем везде. Если такой алгоритм не подходит, то как все это лучше сделать? (Пробовал использовать vector, list и просто массив строк)
TikaraДата: Пятница, 28 Декабря 2012, 12:13 | Сообщение # 10
частый гость
Сейчас нет на сайте
Stealth, я бы Вам посоветовал читать/записывать файл побайтно, что в свою очередь ускорит чтение/запись файла. Но конечно же просто открыть файл блокнотом и посмотреть содержимое не получится.

Предложу такой вариант:

Код
#define BYTE unsigned char

#define NUMBER_OF_OPTIONS 5 // кол-во настроек
#define MAX_LENGTH_NICKNAME 16 // максимальная длина строки

/* Определение индефикаторов настроек для хранения */

#define GSResolution 0
     #define GSR_1024_768 0
     #define GSR_640_480 1

#define GSGraphicsMode 1
     #define GSGM_3D 0
     #define GSGM_2D 1

#define GSGraphicsQuality 2
     #define GSGQ_HIGH 0
     #define GSGQ_MEDIUM 1
     #define GSGQ_LOW 2

#define GSSoundMode 3
     #define GSSM_5_1 0
     #define GSSM_4_1 1
     #define GSSM_2_1 2
     #define GSSM_2_0 3

#define GSSoundVolume 4

void LoadSettings(char * const nickname,BYTE * const gameSettings){
  FILE *file = fopen("settings.set","rb"); // бинарное чтение

  if(!file)
   return;

  fread(nickname,sizeof(char),MAX_LENGTH_NICKNAME, file); // строка находится в начале файла - начнём чтение с неё
  fread(gameSettings,sizeof(BYTE),NUMBER_OF_OPTIONS,file);

  fclose(file);
}

void SaveSettings(const char * const nickname,const BYTE * const gameSettings){
  FILE *file = fopen("settings.set","wb"); // бинарная запись

  fwrite(nickname,sizeof(char),MAX_LENGTH_NICKNAME, file);
  fwrite(gameSettings,sizeof(BYTE),NUMBER_OF_OPTIONS,file);

  fclose(file);
}

int main(){
  char nickname[MAX_LENGTH_NICKNAME] /*= "Name"*/;
  BYTE gameSettings[NUMBER_OF_OPTIONS] /*= {GSR_1024_768,GSGM_3D,GSGQ_MEDIUM,GSSM_2_1,100}*/;

  LoadSettings(nickname,gameSettings);
  //SaveSettings(nickname,gameSettings);
   
  // Воспользуемся настройками

  printf("[ Game Settings ]\nNickname: %s\n", nickname);

  printf("Resolution: ");

  switch(gameSettings[GSResolution]){
  case GSR_1024_768:
   printf("1024x768\n");
   break;
  case GSR_640_480:
   printf("640x480\n");
   break;
  }

  printf("Graphics Mode: ");

  switch(gameSettings[GSGraphicsMode]){
  case GSGM_3D:
   printf("3D\n");
   break;
  case GSGM_2D:
   printf("2D\n");
   break;
  }

  printf("Graphics Quality: ");

  switch(gameSettings[GSGraphicsQuality]){
  case GSGQ_HIGH:
   printf("High\n");
   break;
  case GSGQ_MEDIUM:
   printf("Medium\n");
   break;
  case GSGQ_LOW:
   printf("Low\n");
   break;
  }

  printf("Sound Mode: ");

  switch(gameSettings[GSSoundMode]){
  case GSSM_5_1:
   printf("5.1\n");
   break;
  case GSSM_4_1:
   printf("4.1\n");
   break;
  case GSSM_2_1:
   printf("2.1\n");
   break;
  case GSSM_2_0:
   printf("2.0\n");
   break;
  }

  printf("Sound Volume: %d%%\n", gameSettings[GSSoundVolume]);

  // А можно изменить

  gameSettings[GSGraphicsQuality] = GSGQ_HIGH;
  gameSettings[GSSoundMode] = GSSM_5_1;

  fgetchar();

     return 0;  
}


Но если всё-таки Вам нужно будет записать файл в текстовом виде, то вот как это можно сделать:

Код
void SaveFile( const char * const settings, const char * const keys, int size ){
FILE* file = fopen("settings.txt", "wt");

fprintf(file,"[game]\n");
for(int i=0;i<size;i++)
     fprintf(file,"%s=%s", settings[i], keys[i]); // синтаксис аналогичен printf

fclose(file);
}


Конечно данная реализация будет работать не очень эффективно, но, думаю, суть ясна.
falcowareДата: Пятница, 28 Декабря 2012, 12:17 | Сообщение # 11
старожил
Сейчас нет на сайте
Stealth, надо забить нулями строку nc после выделения памяти, иначе там мусор.
StealthДата: Пятница, 28 Декабря 2012, 22:00 | Сообщение # 12
был не раз
Сейчас нет на сайте
Tikara, спасибо большое за помощь. Я пожалуй сделаю так: скомбинирую ваш вариант (с бинарными файлами) и вариант, который я нашел на просторах интернета. Они будут использоваться отдельно друг от друга.
Если кому интересен этот парсер ini-файлов, то вот.


Сообщение отредактировал Stealth - Пятница, 28 Декабря 2012, 22:01
Форум игроделов » Программирование » C/C++ » Работа с файлами (Неправильно возвращает строку)
  • Страница 1 из 1
  • 1
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг