CFile writes some garbage value - c++

Im wriitng some data in File.But it doesnot write this properly.
Code:
CString sFileName = "C:\\Test.txt";
CFile gpFile;
CString testarr[10] = {"Tom","Ger","FER","DER","SIL","REM","FWE","DWR","SFE","RPOP"};
if (!gpFile.Open( sFileName,CFile::modeCreate|CFile::modeWrite))
{
AfxMessageBox( sFileName + (CString)" - File Write Error");
return;
}
else
{
gpFile.Write(testarr,10);
}
AfxMessageBox("Completed");
gpFile.Close();
It shows the file as

That's probably because you're using CFile incorrectly. The first parameter to CFile::Write should be a buffer whose bytes you'd like to write to the file. However, testarr is more like a "buffer of buffers", since each element of testarr is a string, and a string is itself a sequence of bytes.
What you would need to do instead is either concatenate the elements of testarr, and then call CFile::Write. Or (probably more practical), iterate over testarr printing each string one at a time, e.g. for your particular example, the following should do what you're looking for:
for(int i = 0; i < 10; ++i)
{
gpFile.Write(testarr[i], strlen(testarr[i]));
}
There may be some built-in way to accomplish this, but I'm not really familiar with MFC, so I won't be much help there.

Related

Trying to copy lines from text file to array of strings (char**)

This is my code for allocating memory for the array of strings:
FileReader::FileReader()
{
readBuffer = (char**)malloc(100 * sizeof(char*));
for (int i = 0; i < 100; i++)
{
readBuffer[i] = (char*)malloc(200 * sizeof(char));
}
}
Im alocating 100 strings for 100 lines then allocating 200 chars for each string.
This is my code for reading the lines:
char** FileReader::ReadFile(const char* filename)
{
int i = 0;
File.open(filename);
if (File.is_open())
{
while (getline(File, tmpString))
{
readBuffer[i] = (char*)tmpString.c_str();
i++;
}
return readBuffer;
}
}
and for printing:
for (int i = 0; i <= 5; i++)
{
cout << fileCpy[i];
}
this is the output to terminal:
Picture
As you can see it just repeats the last line of the file as the file just reads:
This is test
line 2
line 3
line 4
line 5
Any idea on whats going on? Why the lines aren't copying correctly?
Replace
readBuffer[i] = (char*)tmpString.c_str();
with
strcpy(readBuffer[i], tmpString.c_str());
Your version just saves a pointers to tmpString in your array. When tmpString changes then that pointer points at the new contents of tmpString (and that's just the best possible outcome). However strcpy actually copies the characters of the string, which is what you want.
Of course, I'm sure it doesn't need saying, but you can avoid all the headache and complication like this
vector<string> readBuffer;
This way there are no more pointer problems, no more manual allocation or freeing of memory, no limits, you aren't limited to 100 lines or 200 characters per line. I'm sure you have a reason for doing things the hard way. but I wonder if it's a good reason.
First of all, you have to switch from C to C++.
Do not allocate memory like that when the only way to do it now in modern C++ is trough smart pointers from the memory header.
Anyways, you do not directly need dynamic allocation here. You have to encapsulate your data within the class and to use the std::vector<std::string> component from the standard library. This vector is a dynamic array that handle all the memory stuff behind the scene for you.
To read all lines of a file :
std::string item_name;
std::vector<std::string> your_buffer;
std::ifstream name_fileout;
name_fileout.open("test.txt");
while (std::getline(name_fileout, item_name))
{
your_buffer.push_back(item_name);
std::cout << item_name;
}
name_fileout.close();

How to read custom string with C++ from binary recursively

I've recently been getting in to IO with C++. I am trying to read a string from a binary file stream.
The custom type is saved like this:
The string is prefixed with the length of the string. So hello, would be stored like this: 6Hello\0.
I am basically reading text from a table (in this case a name table) in a binary file. The file header tells me the offset of this table (112 bytes in this case) and the number of names (318).
Using this information I can read the first byte at this offset. This tells me the length of the string (e.g. 6). So I'll start at the next byte and read 5 more to get the full string "Hello". This seems to work fine with the first name at the offset. trying to recursively read the rest provides a lot of garbage really. I've tried using loops and recursive functions but its not working out so well. Not sure what the problem is, so reverted to the original one name retrieval method. Here's the code:
int printName(fstream& fileObj, __int8 buff, DWORD offset, int& iteration){
fileObj.seekg(offset);
fileObj.read((char*)&buff, sizeof(char));
int nameSize = (int)buff;
char* szName = new char[nameSize];
for(int i=1; i <= nameSize; i++){
fileObj.seekg(offset+i);
fileObj.read((char*)&szName[i-1], sizeof(char));
}
cout << szName << endl;
return 0;
}
Any idea how to iterate through all 318 names without creating dodgy output?
Thanks for taking the time to look through this, your help is greatly appreciated.
You're overcomplicating a bit - there's no need to seek to the next sequential read.
Removing unused and pointless parameters, I would write this function something like this:
void printName(fstream& fileObj, DWORD offset) {
char size = 0;
if (fileObj.seekg(offset) && fileObj.read(&size, sizeof(char)))
{
char* name = new char[size];
if (fileObj.read(name, size))
{
cout << name << endl;
}
delete [] name;
}
}

C++ use regex on char array with \0's and get result

I want to use regex on a binary file, which contains 0 bytes, which renders me unable to use a string. I'm using a char array, and I'm able to use regex on the char array.
Buffer is a copy of the file mapped into memory, and read is the total size. This code works, but now I want to get the result back from the function. How do I do this?
if(std::regex_search(buffer, buffer + read, *params->pattern))
{
std::cout << "Found.";
}
I did not test this but it should work..
auto it = std::cregex_iterator(&buffer[0], &buffer[read], *params->pattern);
for (int i = 0; i < it->size(); ++i)
{
const char* str = (*it)[i].str();
size_t size = (*it)[i].length();
std::cout.write(str, size);
}
I've tested this only on regular strings.. Not strings containing null chars. I don't see why it shouldn't work though because it does return a sequence of chars and the length of said sequence.

Newline character in Text Document?

I wrote a pretty simple function that reads in possible player names and stores them in a map for later use. Basically in the file, each line is a new possible player name, but for some reason it seems like all but the last name has some invisible new line character after it. My print out is showing it like this...
nameLine = Georgio
Name: Georgio
0
nameLine = TestPlayer
Name: TestPlayer 0
Here is the actual code. I assume I need to be stripping something out but I am not sure what I need to be checking for.
bool PlayerManager::ParsePlayerNames()
{
FileHandle_t file;
file = filesystem->Open("names.txt", "r", "MOD");
if(file)
{
int size = filesystem->Size(file);
char *line = new char[size + 1];
while(!filesystem->EndOfFile(file))
{
char *nameLine = filesystem->ReadLine(line, size, file);
if(strcmp(nameLine, "") != 0)
{
Msg("nameLine = %s\n", nameLine);
g_PlayerNames.insert(std::pair<char*, int>(nameLine, 0));
}
for(std::map<char*,int>::iterator it = g_PlayerNames.begin(); it != g_PlayerNames.end(); ++it)
{
Msg("Name: %s %d\n", it->first, it->second);
}
}
return true;
}
Msg("[PlayerManager] Failed to find the Player Names File (names.txt)\n");
filesystem->Close(file);
return false;
}
You really need to consider using iostreams and std::string. The above code is SO much more simpler if you used the C++ constructs available to you.
Problems with your code:
why do you allocate a buffer for a single line which is the size of the file?
You don't clean up this buffer!
How does ReadLine fill the line buffer?
presumably nameLine points to the begining of the line buffer, if so, given in the std::map, the key is a pointer (char*) rather than a string as you were expecting, and the pointer is the same! If different (i.e. somehow you read a line and then move the pointer along for each name, then std::map will contain an entry per player, however you'll not be able to find an entry by player name as the comparison will be a pointer comparison rather than a string comparison as you are expecting!
I suggest that you look at implementing this using iostreams, here is some example code (without any testing)
ifstream fin("names.txt");
std::string line;
while (fin.good())
{
std::getline(fin, line); // automatically drops the new line character!
if (!line.empty())
{
g_PlayerNames.insert(std::pair<std::string, int>(line, 0));
}
}
// now do what you need to
}
No need to do any manual memory management, and std::map is typed with std::string!
ReadLine clearly includes the newline in the data it returns. Simply check for and remove it:
char *nameLine = filesystem->ReadLine(line, size, file);
// remove any newline...
if (const char* p_nl = strchr(nameLine, '\n'))
*p_nl = '\0';
(What this does is overwrite the newline character with a new NUL terminator, which effectively truncates the ASCIIZ string at that point.
Most likely the ReadLinefunction also reads the newline character. I suppose your file does not have a newline at the very last line, thus you do not get a newline for that name.
But until I know what filesystem, FileHandle_t, and Msg is, it is very hard to determine where the issue could be.

What is the proper method of reading and parsing data files in C++?

What is an efficient, proper way of reading in a data file with mixed characters? For example, I have a data file that contains a mixture of data loaded from other files, 32-bit integers, characters and strings. Currently, I am using an fstream object, but it gets stopped once it hits an int32 or the end of a string. if i add random data onto the end of the string in the data file, it seems to follow through with the rest of the file. This leads me to believe that the null-termination added onto strings is messing it up. Here's an example of loading in the file:
void main()
{
fstream fin("C://mark.dat", ios::in|ios::binary|ios::ate);
char *mymemory = 0;
int size;
size = 0;
if (fin.is_open())
{
size = static_cast<int>(fin.tellg());
mymemory = new char[static_cast<int>(size+1)];
memset(mymemory, 0, static_cast<int>(size + 1));
fin.seekg(0, ios::beg);
fin.read(mymemory, size);
fin.close();
printf(mymemory);
std::string hithere;
hithere = cin.get();
}
}
Why might this code stop after reading in an integer or a string? How might one get around this? Is this the wrong approach when dealing with these types of files? Should I be using fstream at all?
Have you ever considered that the file reading is working perfectly and it is printf(mymemory) that is stopping at the first null?
Have a look with the debugger and see if I am right.
Also, if you want to print someone else's buffer, use puts(mymemory) or printf("%s", mymemory). Don't accept someone else's input for the format string, it could crash your program.
Try
for (int i = 0; i < size ; ++i)
{
// 0 - pad with 0s
// 2 - to two zeros max
// X - a Hex value with capital A-F (0A, 1B, etc)
printf("%02X ", (int)mymemory[i]);
if (i % 32 == 0)
printf("\n"); //New line every 32 bytes
}
as a way to dump your data file back out as hex.