Best way to compare input values to read values from files - c++

I am relatively new to c++ programming and I have hit one of my first major snags in all of this..
I am trying to figure out how to read a value/character from a generic ".txt" file that is on notepad. With that comparison I want to determine whether or not to read that entire line, but I can't seem to just read the single one or two digit number, I got it to read the whole line using { 'buffername'.getline(variable, size) } but when I try to change the 'size' to a specific number it gives me a comparison error saying that its invalid to switch to 'int' or 'char' (depending on how I declare the variable).
Any help is appreciated.
Thanks

int length = 2;
char * buffer;
ifstream is;
is.open ("test.txt", ios::binary );
// allocate memory:
buffer = new char [length];
// read 2 char
is.read (buffer,length);
//Compare the character and decide
delete[] buffer;
return 0;

You'll want to use an ifstream to get the value (ref 1).
Something like the following should work. Here I use a word of type std::string, but you can replace that with other types to read them (ie: int, double, etc...).
std::ifstream f("somefile.txt");
std::string word;
std::string line;
if(f >> word){
if(<the comparison>){
line = f.getline();
}
}
Here's an extended example of how to use the ifstream

First of all, for performance reasons it is a bad idea to read 1 byte at a time.
I suggest this alternative:
You would be better off reading in the whole line, and then using character array.
char variable[1000];
read your line in from the file into variable.
if (variable[1]=='c') { printf("Byte 2 (remember 0 offset) is compared for the letter c";}
getting a 2 digit #
number=((variable[3]-48)*10)+(variable[4]-48);
You have to subtract 48 because in ASCII the number 0 is 48.

Related

read the whole binary into a buffer then resolve it in specific format

Here is my C++ homework. Given a binary file, this file consists of some data units. Every data unit contains two parts. The first part is 1 char and the second part is 1 int. Read the whole file into a buffer at a time and then extract all data units from the buffer.
Now I've read the file into a buffer successfully like this:
char* readBinaryFile(const char* fileName) {
ifstream file(fileName, ios::binary || ios::ate);
// get the size of file
streampos beg, end;
beg = file.tellg();
file.seekg(0,ios::end);
end = file.tellg();
long size = end - beg;
char* buffer = new char[size];
// now read the file into buffer
file.seekg(0, ios::beg);
file.read(buffer, size);
file.close();
return buffer;
}
So my problem is how can I get the data unit from the buffer?
I'm not going to write the code for you, but think about this for a moment...
At buffer[0] is your first char. At buffer[1] through buffer[4] is your first int. It repeats, so buffer[5] is the character for the second set of data.
There are five bytes for the character and the int together. If you know the amount of data you've read, you could divide that by 5 and know the number of "sets" of data there is.
You can now use something like a for loop to iterate from zero to the numbers of sets minus one. Let's say this iterator variable is i, then you could access the character of each "set" of data with buffer[i * 5], the first byte of the int at buffer[i * 5 + 1], etc.
So, a for loop and a little bit of math will help you extract the information from that buffer. You'll have 5 individual bytes, and you'll need to reassemble 4 of those bytes back into an int. There are a variety of ways of accomplishing this, which I'll let you attempt to discover.
Could your issue stem from the fact that you're using:
ios::binary || ios::ate
when I think you mean:
ios::binary | ios::ate
The former evaluates to "1", since binary logical-or at-end is "true", the latter is a bitmask that says "open this file in binary mode, and at the end". The way you have written it is actually the equivalent of
ios::app

Reading text file in blocks-c++

string lineValue;
ifstream myFile("file.txt");
if (myFile.is_open()) {
//getline(myFile, lineValue);
//cout<<lineValue;
while (getline(myFile, lineValue)) {
cout << lineValue << '\n';
}
myFile.close();
}
else cout << "Unable to open file";
The txt file formate is like this
0 1
1 2
2 3
3 4
4 5
5 5
6 6
7 7
8 8
9 9
Above code is reading data from a text file line by line, but the text file size is quite large (10GB).
So how to read data from the file in chunks/blocks with less I/O and efficiently ?
If you are thinking of reading in large chunks of data then you will be using a technique called buffering. However, ifstream already provides buffering so my first step would be to see if you can get ifstream doing the job for you.
I would set a much larger buffer than the default in you're ifstream. Something like
const int BUFSIZE = 65536;
std::unique_ptr<char> buffer(new char[BUFSIZE]);
std::ifstream is;
is.rdbuf()->pubsetbuf(buffer.get(), BUFSIZE);
is.open(filename.c_str());
const int LINESIZE = 256;
char line[LINESIZE];
if (is) {
for (;;) {
is.getline(line, LINESIZE);
// check for errors and do other work here, (and end loop at some point!)
}
}
is.close();
Make sure your buffer lives as long as the ifstream object that uses it.
If you find the speed of this is still insufficient, then you can try reading chunks of data with ifstream::read. There is no guarantee it will be faster, you'll have to time and compare the options. You use ifstream::read something like this.
const int BUFSIZE = 65536;
std::unique_ptr<char> buffer(new char[BUFSIZE]);
is.read(buffer.get(), BUFSIZE);
You'll have to take care writing the code to call ifstream.read taking care to deal with the fact that a 'line' of input may get split across consecutive blocks (or even across more than two blocks depending upon your data and buffer size). That's why you want to modify ifstream's buffer as you're first option.
If and only if the text lines are the same length, you could simply read the file in using std::istream::read();.
The size of the block to read would be:
block_size = text_line_length * number_of_text_lines;
If you are brave enough to handle more complexity or your text lines are not equal lengths, you could read an arbitrary length of characters into a vector and process the text from the vector.
The complexities come into play when a text line overflows a block. Think of handling the case where only part of the sentence is available at the end of the block.

Quickly convert raw data to hex string in c++

I'm reading data from a file and trying to display the raw data as 2 digit hex strings.
I'm using the Qt framework, specifically the QTextEdit.
I've tried a bunch of different approaches and have almost accomplished what I want it to do, however it has some unexpected errors I don't know anything about.
Currently this is my implementation:
1) Read in the data:
ifstream file (filePath, ios::in|ios::binary|ios::ate);
if (file.is_open())
{
size = file.tellg();
memblock = new char [size+1];
file.seekg(0, ios::beg);
file.read(memblock, size);
file.close();
}
2) Create a single QString that will be used (because QTextEdit requires a QString):
QString s;
3) Loop through the array appending each successive character to the QString s.
int count = 0;
for(i=0;i<size;i++)
{
count++;;
s.append(QString::number(memblock[i], 16).toUpper());
s.append("\t");
if (count == 16)
{
s.append("\n");
count -= 16;
}
}
Now this works fine, except when it reaches a character FF, it appears as FFFFFFFFFFFFFFFF
So my main questions are:
Why do only the 'FF' characters appear as 'FFFFFFFFFFFFFFFF' instead?
Is there a way to convert the char data to base 16 strings without using QString::number?
I want this implementation to be as fast as possible, so if something like sprintf could work, please let me know, as I would guess that might be faster that QString::number.
QString can't be used for binary data. You should use QByteArray instead. It can be easily created from char* buffer and can be easily converted to hex string using toHex.
QByteArray array(memblock, size);
textEdit->setText(QString(array.toHex()));
QString::number doesn't have an overload that takes a char, so your input is being promoted to an int; consequently you're seeing the effects of sign extension. You should be seeing similar behavior for any input greater than 0x7F.
Try casting the data prior to calling the function.
s.append(QString::number(static_cast<unsigned char>(memblock[i]), 16).toUpper());

Reading binary text into array?

I have a program that I need to read binary text into. I read the binary text via a redirection:
readData will be an executable made by my Makefile.
Example: readData < binaryText.txt
What I want to do is read the binary text, and store each character in the binary text file as a character inside a char array. The binary text is made up of 32 This is my attempt at doing so...
unsigned char * buffer;
char d;
cin.seekg(0, ios::end);
int length = cin.tellg();
cin.seekg(0, ios::beg);
buffer = new unsigned char [length];
while(cin.get(d))
{
cin.read((char*)&buffer, length);
cout << buffer[(int)d] << endl;
}
However, I keep getting a segmentation fault on this. Might anyone have any ideas on how to read binary text into a char array? Thanks!
I'm more a C programmer rather than a C++, but I think that you should have started your while loop
while(cin.get(&d)){
The easiest would be like this:
std::istringstream iss;
iss << std::cin.rdbuf();
// now use iss.str()
Or, all in one line:
std::string data(static_cast<std::istringstream&>(std::istringstream() << std::cin.rdbuf()).str());
Something like this should do the trick.
You retrieve the filename from the arguments and then read the whole file in one shot.
const char *filename = argv[0];
vector<char> buffer;
// open the stream
std::ifstream is(filename);
// determine the file length
is.seekg(0, ios_base::end);
std::size_t size = is.tellg();
is.seekg(0, std::ios_base::beg);
// make sure we have enough memory space
buffer.reserve(size);
buffer.resize(size, 0);
// load the data
is.read((char *) &buffer[0], size);
// close the file
is.close();
You then just need to iterate over the vector to read characters.
The reason why you are getting segmentation fault is because you are trying to access an array variable using a character value.
Problem:
buffer[(int)d] //d is a ASCII character value, and if the value exceeds the array's range, there comes the segfault.
If what you want is an character array, you already have that from cin.read()
Solution:
cin.read(reinterpret_cast<char*>(buffer), length);
If you want to print out, just use printf
printf("%s", buffer);
I used reinterpret_cast because it thought it is safe to convert to signed character pointer since most characters that are used would range from 0 ~ 127. You should know that character values from 128 to 255 would be converted wrongly.

Width as a variable when using fscanf [duplicate]

This question already has answers here:
How to prevent scanf causing a buffer overflow in C?
(6 answers)
Closed 6 years ago.
I am trying to read in a certain portion of a file and that amount of data is different per line but I know how how many bytes of info I want. Like this:
5bytes.byte1byte2byte3byte4byte5CKSum //where # of bytes varies for each line (and there is no period only there for readability)
Actual data:
05AABBCCDDEE11
03AABBCC22
04AABBCCDD33
So I want to have my width be a variable like this:
fscanf_s(in_file,"%variableX", &iData);
Is this possible, because right now I'm thinking I have to create a case statement?
Unfortunately, no, there's no modifier like '*' for printf that causes scanf to get its field width or precision from a variable. The closest you can come is dynamically creating the format string:
char format[8];
sprintf(format, "%%%dX", width);
fscanf(in_file, format, &iData);
If you really want to be able to adjust the fscanf format programmatically, you could try stack-allocating a string with enough space, and then generating the format like so:
e.g.
char formatString[100];
// writes "%max_size[0-9]", substituting max_size with the proper digits
sprintf(formatString, "%%%d[0-9]", MAX_SIZE);
fscanf(fp, formatString, buffer); // etc...
fscanf with %X will stop at a newline automatically, right? If the fields really are newline-terminated (as in your example), then can't you just call
fscanf(in_file, "%X", &iData);
and let fscanf figure out where the end is?
You might also consider using C++ streams.
#include <ifstream>
#include <iostream>
// open the file and create a file input stream
ifstream file("test.txt" , ios::in | ios::binary);
// loop through the whole file
while (ifs.good())
{
// extract one byte as the field width
unsigned char width;
file.read(&width, 1);
// extract width number of unformatted bytes
char * bytes = new char[width];
file.read(bytes, width);
// process the bytes
...
delete [] bytes;
// skip EOL characters if needed
// file.seekg(1, ios_base::cur)
}
file.close();
A simpler way if the newlines are included as you seem to indicate, would be to use getLine(). Check out http://www.cplusplus.com/reference/iostream/ifstream/ for more ways to use read(), get(), getLine() and lots of other great stream functions.
I think the simplest would be to use fread() like this:
fread(buffer, nbytes, sizeof(char), in_file);