[C++] Odczytywanie pliku, dziwne znaki

0

Mam taki kod:

			f.open(file);

			if(f)
			{
				//getting file length
				f.seekg(0, std::ios::end);
				length = (int)f.tellg();
				f.seekg(0, std::ios::beg);

				if(length > 0 && (buffer = (char*)malloc((length) * sizeof(char))) != NULL)
				{
					f.read(buffer, length);
					logprintf(buffer);


				}



			}

mały opis:

  • logprintf - funkcja wyświetająca - piszę plugin do pewnego systemu wbudowanego
  • inicjalizacja f:
std::ifstream f;
  • inicjalizacja buffer:
    char *buffer = NULL;

i jest dobrze odczytywany, lecz do końca ciągu znaków dodawane są dziwne znaki, przykład:
1ýýýýÝ
a właściwa treść pliku to:
1

Jak temu zapobiec? Przy innych plikach również dochodzą jeszcze inne krzaki.

0

Po wczytaniu pliku możesz go sobie sprawdzać w ten sposób:

for(int i = 0; i < length; i++)
     if(buffer[i] < 1 || buffer[i] > 123)
     {
          buffer[i] = NULL;
          break;
     }

Dzięki temu niejako zamkniesz łańcuch.

0

Rozwiązanie niby dobre, ale chciałbym zachować również znaki specjalne, które jednak mogłyby być w pliku. Przy tym problemie boli mnie jedno:

                                length = (int)f.tellg();

po usunięciu (int) z tej linijki, wyskakuje warning:
warning C4244: '=' : conversion from 'std::streamoff' to 'int', possible loss of data

coś mi mówi, że to on ma wpływ na te znaki, lecz pisząc ten skrypt, kierowałem się przykładem na cplusplus.com: http://www.cplusplus.com/reference/iostream/istream/tellg/</del>

buffer[length] = NULL;

Masakra :D

0

Przecież przy czymś takim zachowasz znaki specjalne, przynajmniej te, które są zawarte w ASCII.

0

Przy twoim przykładzie, ciąg znaków zatrzymywał się przy 'ł' (pierwszy polski znak, wtedy testowałem inny plik), ASCII chyba jest do 255... A problem rozwiązany, zwiększyłem rozmiar zarezerwowanej pamięci o 1 i dodałem linijkę, w poście powyżej.

EDIT:
Żałosne, zepsuło się coś. Dobra, odstawię to na bok, później się tym zajmę.

0

O właśnie :D wiedziałem, że coś z "= NULL" haha :D

0

To co widzisz to są śmieci z pamięci, bo niby na jakiej podstawie funkcja logprintf ma wiedzieć gdzie się kończy napis?
f.read czyta dane binarnie, więc nie dodaje znaku końca tekstu (zera) na końcu.
Rozwiązania są dwa.

  1. lamerskie:
if(length > 0 && (buffer = (char*)malloc((length+1) * sizeof(char))) != NULL) {
    f.read(buffer, length);
    buffer[length]=0; // dopisanie zera na końcu
    logprintf(buffer);
}
  1. bardziej poprawne to poprawić logprintf tak by pobierało długość bufora (podasz tam length):
void logprintf(char *, unsigned int count);
0
  1. Lamerskie nie działa poprawnie.

Przy pliku o treści 1, działa ok, ale przy

eh=4gueht
wog=eryułąą
woger=ergreg
bntehr=erherh

wysiada, wyświetla

eh=4gueht
wog=eryułąą
woger=ergreg
bntehr=erherhÍÍÍ

A to poprawne, to nie za bardzo mogę zmodyfikować logprintf, gdyż ono jest związane z SDK (zdradzę sekret: programuję w AMX, lecz nie jest to CS), a to jest jakoś dziwnie wykonane, np. tak wygląda górna część, związana z inicjalizacją pluginu:

#include "../SDK/amx/amx.h"
#include "../SDK/plugincommon.h"
#include <iostream>
#include <fstream>

typedef void (*logprintf_t)(char* format, ...);

logprintf_t logprintf;
void **ppPluginData;
extern void *pAMXFunctions;

PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports() 
{
	return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES;
}

PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData) 
{
	pAMXFunctions = ppData[PLUGIN_DATA_AMX_EXPORTS];
	logprintf = (logprintf_t)ppData[PLUGIN_DATA_LOGPRINTF];

	logprintf("Plugin wczytany!");
	return true;
}

dalej w kodzie są tylko własne funkcje, zarządzające stringami, a na końcu:

PLUGIN_EXPORT int PLUGIN_CALL AmxLoad(AMX *amx) 
{
	return amx_Register(amx, INI_Natives, -1);
}

PLUGIN_EXPORT int PLUGIN_CALL AmxUnload(AMX *amx) 
{
	return AMX_ERR_NONE;
}

a, i jeśli podpowiecie, to mogę zmienić rodzaj odczytywania plików, jakiś czas temu testowałem fopen, fread i również były te znaki (czyli jak w tym temacie jest napisane, binarnie odczytuje).

EDIT:
Rozwiązane :D

			f = fopen(file, "r");

			if(f)
			{
				fseek(f, 0, SEEK_END);
				length = ftell(f);
				rewind(f);

				if(length > 0 && (buffer = (char*)malloc((length + 1) * sizeof(char))) != NULL)
				{
					char c; int pos = 0;
					while((c = fgetc(f)) != EOF)
						buffer[pos++] = c;

					buffer[pos] = NULL;
				}

			}
0

Najwyraźniej, nadal plik jest konwertowany jak by był tekstem. Każda dwu-bajtowe zakończenie linii LF CR jest zastępowane przez jedno-bajtowe CR i dlatego dane ci się skróciły.
To można poprawić na dwa sposoby:

  1. otworzyć plik binarnie
f.open(file, ifstream::in | ifstream::binary);
  1. odczytać ile tak naprawdę bajtów wczytano:
if(length > 0 && (buffer = (char*)malloc((length+1) * sizeof(char))) != NULL) {
    f.read(buffer, length);
    length = f.gcount();
    buffer[length]=0; // dopisanie zera na końcu
    logprintf(buffer);
}

W sumie to nie rozumiem czemu koniecznie chcesz wczytać wszystko binarnie, a nie po prostu nie skorzystać ze sformatowanego strumienia (std::getline, operator >>). W końcu ten twój plik jest czysto tekstowy.

1 użytkowników online, w tym zalogowanych: 0, gości: 1