C++ Convert char array to string array - c++

I have next C++ code in VS2019 under Windows 10:
char const* const fileName = "random_StringArray_10000000";
FILE* infile;
long fileSize;
char* buffer;
size_t readBytes;
infile = fopen(fileName, "rb");
if (infile == NULL)
{
fputs("File error", stderr); exit(1);
}
fseek(infile, 0, SEEK_END);
fileSize = ftell(infile);
rewind(infile);
buffer = (char*)malloc(sizeof(char) * fileSize);
if (buffer == NULL)
{
fputs("Memory error", stderr); exit(2);
}
auto start = chrono::steady_clock::now();
readBytes = fread(buffer, 1, fileSize, infile);
auto end = chrono::steady_clock::now();
if (readBytes != fileSize)
{
fputs("Reading error", stderr); exit(3);
}
fclose(infile);
free(buffer);
auto elapsed_ms = chrono::duration_cast<chrono::milliseconds>(end - start);
cout << "Elapsed ms: " << elapsed_ms.count() << endl;
cout << "String count: " << stringCount << endl;
system("pause");
return 0;
This method used because it is fastest way to read file from disk under VS2019.
Now i need to convert char array to the string array.
random_StringArray_10000000 - UTF8 text file.
Strings lenght 8 - 120 symbols.
Hex view of this file:
0x0D 0x0A separate strings.
Which fastest way to convert char array (buffer) to the C++ string array?

There seems to be a regularity to your data, all strings are eight characters long and separated by the same two characters. With that in mind the following seems fairly fast.
size_t arraySize = readBytes/10;
std::string* array = new std::string[arraySize];
for (size_t i = 0; i < arraySize; ++i)
array[i].assign(buffer + 10*i, 8);
Of course timing is necessary to be sure what is fastest.

Reading lines of text from a file is much simpler if you use the classes from the c++ standard library.
This should be all of the code you need:
#include <fstream>
#include <vector>
#include <string>
#include <iostream>
int main()
{
char const* const fileName = "random_StringArray_10000000";
std::ifstream in(fileName);
if (!in)
{
std::cout << "File error\n";
return 1;
}
std::vector<std::string> lines;
std::string line;
while (std::getline(in, line))
{
lines.push_back(std::move(line));
}
return 0;
}

char as[ ] = "a char array"; : is a char array
char const* const fileName = "random_StringArray_10000000"; : is a c string
This is also a c string:
char* cs = const_cast<char*>( fileName );
If you want std::string use:
std::string s(as);
I wasn't sure which string conversion you wanted so I just added what I could off the top of my head. But here's a compilable example too.

Related

Flatbuffers: write read binary file issue in c++?

My schema, encoder and decoder looks as below.
Schema :
namespace Myclient.sample;
table Person {
age: short;
}
root_type Person;
Encoder:
int main(int argc, char *argv[])
{
flatbuffers::FlatBufferBuilder builder(1024);
auto name = builder.CreateString("Mr Test");
PersonBuilder mybuilder(builder);
mybuilder.add_age(20);
auto orc = mybuilder.Finish();
builder.Finish(orc);
uint8_t *buf = builder.GetBufferPointer();
int size = builder.GetSize();
ofstream wf(argv[1], ios::out | ios::binary);
wf.write((char*) &buf, size); // overwrite
wf.close();
return 0;
}
Decoder:
int main(int argc, char *argv[])
{
//Read BIN file
std::ifstream infile;
infile.open(argv[1], std::ios::binary | std::ios:: in);
infile.seekg(0, std::ios::end);
int length = infile.tellg();
infile.seekg(0, std::ios::beg);
char *data = new char[length];
infile.read(data, length);
infile.close();
flatbuffers::Verifier verifier(reinterpret_cast< unsigned char*> (data), length);
bool ok = VerifyPersonBuffer(verifier);
cout << " verify value2: " << ok << endl;
auto per = GetPerson(data);
if (per)
{
cout << " person decoded" << endl;
cout << "age is " << per->age() << endl;
}
return 0;
}
output of decoder:
verify value2: 0
person decoded
Issue:
could not decoded. is there any issue with biniary file read write, or schema definition.
please help.
Thanks.
wf.write((char*) &buf, size); will happily write the address of buf to that file followed by a large amount of garbage. The compiler was trying to warn you but you shut it up without reading the error. Change to buf and at least that problem is solved.

std::ifstream.read() doesn't return anything to my buffer

When I am reading file with function read(), this function doesn't save data to my buffer smoke. I'm trying to read a file and save it to smoke with binary content.
How can I do it better, with vectors?
std::ifstream file("favicon.ico", std::ios::binary);
char ak47xd[1024];
std::string testxcs = "";
if (file.is_open()) {
file.seekg(0, file.end);
const size_t length = file.tellg();
file.seekg(0, file.beg);
char smoke[318];
file.read(smoke, length);
printf("sss: %s\n",smoke);
for (int i = 0; i < length; i++) {
printf("sk: %c\n",smoke[i]);
testxcs += smoke[i];
//printf("%i : %X\n", i, smoke[i] & 0xFF);
//testxcs += (smoke[i] & 0xFF);
//printf("Smoke: %s\n",testxcs.c_str());
}
}
Output:
Here picture
Here problem
You are reinterpret_casting a char** to char*, your program's behaviour is undefined. Probably what is happening is the bytes are being written somewhere else.
You don't need three buffers to read into
#include <iostream>
#include <string>
std::ifstream file("favicon.ico", std::ios::binary);
if (file) {
file.ignore( std::numeric_limits<std::streamsize>::max() );
std::streamsize length = file.gcount();
file.clear(); // Since ignore will have set eof.
file.seekg( 0, std::ios_base::beg );
std::string testxcs(length, 0);
file.read(testxcs.data(), length);
std::cout << "sss: " << testxcs << "\n";
for (char c : testxcs)
{
std::cout << "sk: " << c << "\n";
}
}

Write vector of unsigned char to binary file c++

I am reading binary file cmd.exe into unsigned chars array. Total bytes read into bytes_read are 153. I converted it to base64 string and then decode this string back (code from 2nd answer base64 decode snippet in c++) into vector<'BYTE>. Here BYTE is unsigned char.
decodedData.size() is also 153. But when I write this vector to file in binary mode to get my cmd.exe file again I get only 1 KB file. What thing I missed?
// Reading size of file
FILE * file = fopen("cmd.exe", "r+");
if (file == NULL) return 1;
fseek(file, 0, SEEK_END);
long int size = ftell(file);
fclose(file);
// Reading data to array of unsigned chars
file = fopen("cmd.exe", "r+");
unsigned char * myData = (unsigned char *)malloc(size);
int bytes_read = fread(myData, sizeof(unsigned char), size, file);
fclose(file);
std::string encodedData = base64_encode(&myData[0], bytes_read);
std::vector<BYTE> decodedData = base64_decode(encodedData);
////write data to file
ofstream outfile("cmd.exe", ios::out | ios::binary);
outfile.write((const char *)decodedData.data(), decodedData.size());
Update:
Thanks #chux for suggesting "r+" --> "rb+" Problem resolved.
You marked this as C++.
This is one C++ approach using fstream to read a binary file. To simplify for this example, I created a somewhat bigger m_buff than needed. From the comments, it sounds like your fopen("cmd.exe", "r+") was in error, so I'm only providing a C++ binary read.
Method tReader() a) opens a file in binary mode, b) reads the data into m_buff, and c) captures gCount for display.
It also demonstrates one possible use of chrono to measure duration.
#include <chrono>
// 'compressed' chrono access --------------vvvvvvv
typedef std::chrono::high_resolution_clock HRClk_t;
typedef HRClk_t::time_point Time_t;
typedef std::chrono::microseconds US_t;
using namespace std::chrono_literals; // suffixes 100ms, 2s, 30us
#include <iostream>
#include <fstream>
#include <cassert>
class T516_t
{
enum BuffConstraints : uint32_t {
Meg = (1024 * 1024),
END_BuffConstraints
};
char* m_buff;
int64_t m_gCount;
public:
T516_t()
: m_buff (nullptr)
, m_gCount (0)
{
m_buff = new char[Meg];
}
~T516_t() = default;
int exec()
{
tReader();
return(0);
}
private: // methods
void tReader()
{
std::string pfn = "/home/dmoen/.wine/drive_c/windows/system32/cmd.exe";
// open file in binary mode
std::ifstream sIn (pfn, std::ios_base::binary);
if (!sIn.is_open()) {
std::cerr << "UNREACHABLE: unable to open sIn " << pfn
<< " priviledges? media offline?";
return;
}
Time_t start_us = HRClk_t::now();
do
{
// perform read
sIn.read (m_buff, Meg);
// If the input sequence runs out of characters to extract (i.e., the
// end-of-file is reached) before n characters have been successfully
// read, buff contains all the characters read until that point, and
// both eofbit and failbit flags are set
m_gCount = sIn.gcount();
if(sIn.eof()) { break; } // exit when no more data
if(sIn.failbit ) {
std::cerr << "sIn.faileBit() set" << std::endl;
}
}while(1);
auto duration_us = std::chrono::duration_cast<US_t>(HRClk_t::now() - start_us);
sIn.close();
std::cout << "\n " << pfn
<< " " << m_gCount << " bytes"
<< " " << duration_us.count() << " us"
<< std::endl;
} // int64_t tReader()
}; // class T516_t
int main(int , char**)
{
Time_t start_us = HRClk_t::now();
int retVal = -1;
{
T516_t t516;
retVal = t516.exec();
}
auto duration_us = std::chrono::duration_cast<US_t>(HRClk_t::now() - start_us);
std::cout << " FINI " << duration_us.count() << " us" << std::endl;
return(retVal);
}
One typical output on my system looks like:
/home/dmoen/.wine/drive_c/windows/system32/cmd.exe 722260 bytes 1180 us
FINI 1417 us
Your results will vary.
Your ofstream use looks good (so did not replicate).

Why am I getting an std::bad_alloc error

I'm having an issue when running the code below. Every time I set the while loop to reach the .eof() it returns a std::bad_alloc
inFile.open(fileName, std::ios::in | std::ios::binary);
if (inFile.is_open())
{
while (!inFile.eof())
{
read(inFile, readIn);
vecMenu.push_back(readIn);
menu.push_back(readIn);
//count++;
}
std::cout << "File was loaded succesfully..." << std::endl;
inFile.close();
}
It runs fine if I set a predetermined number of iterations, but fails when I use the EOF funtion. Here's the code for the read function:
void read(std::fstream& file, std::string& str)
{
if (file.is_open())
{
unsigned len;
char *buf = nullptr;
file.read(reinterpret_cast<char *>(&len), sizeof(unsigned));
buf = new char[len + 1];
file.read(buf, len);
buf[len] = '\0';
str = buf;
std::cout << "Test: " << str << std::endl;
delete[] buf;
}
else
{
std::cout << "File was not accessible" << std::endl;
}
}
Any help you can provide is greatly appreciated.
NOTE: I failed to mention that vecMenu is of type std::vector
and menu is of type std::list
The main problems I see are:
You are using while (!inFile.eof()) to end the loop. See Why is iostream::eof inside a loop condition considered wrong?.
You are not checking whether calls to ifstream::read succeeded before using the variables that were read into.
I suggest:
Changing your version of read to return a reference to ifstream. It should return the ifstream it takes as input. That makes it possible to use the call to read in the conditional of a loop.
Checking whether calls to ifstream::read succeed before using them.
Putting the call to read in the conditional of the while statement.
std::ifstream& read(std::fstream& file, std::string& str)
{
if (file.is_open())
{
unsigned len;
char *buf = nullptr;
if !(file.read(reinterpret_cast<char *>(&len), sizeof(unsigned)))
{
return file;
}
buf = new char[len + 1];
if ( !file.read(buf, len) )
{
delete [] buf;
return file;
}
buf[len] = '\0';
str = buf;
std::cout << "Test: " << str << std::endl;
delete[] buf;
}
else
{
std::cout << "File was not accessible" << std::endl;
}
return file;
}
and
inFile.open(fileName, std::ios::in | std::ios::binary);
if (inFile.is_open())
{
std::cout << "File was loaded succesfully..." << std::endl;
while (read(inFile, readIn))
{
vecMenu.push_back(readIn);
menu.push_back(readIn);
//count++;
}
inFile.close();
}

pattern matching for loop repeating more than desired

I've never used string or string functions until today and I'm running into a problem that I don't understand. This program as is, should just accept a command line argument, load the file and display it to memory. However it displays it multiple times. I'm pretty sure the for loop is the problem, but it is the same technique as what is used in the programming reference I am using.
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
char* getFile( char* fileName ){
std::fstream inFile( fileName );
if( !inFile ) std::cout << "Could not open " << fileName << ".\n";
else{
inFile.seekg(0,inFile.end);
int len = inFile.tellg();
inFile.seekg(0,inFile.beg);
char* buffer = new char[len];
inFile.read( buffer, len);
inFile.close();
std::cout.write(buffer,len);
return buffer;
}
}
int main(int argc, char** argv){
if(argc != 2) std::cout << "Parameter required\n";
else{
std::string f = getFile( argv[1] );
for( size_t i = f.find( 0x0A, 0 ); i != std::string::npos ; i = f.find( 0x0A, i) ){
std::cout << f.substr(0,i)<<std::endl;
i++;
}
}
}
I see at least one of the problems with my code. I re-wrote the loop as a while loop because it was easier to follow and paid a little more attention to where I am starting and stopping. However it still seems to be printing twice.
int main(int argc, char** argv){
if(argc != 2) std::cout << "Parameter required\n";
else{
std::string f = getFile( argv[1] );
size_t start = 0;
size_t end = 1;
while( end != std::string::npos ){
end = f.find( 0x0A, start );
std::cout << f.substr(start,end)<<std::endl;
start = ( end + 1 );
}
This is because you have two printing statements that are displaying the contents of the file.
The first print statement is this one:
std::cout.write(buffer,len);
The second one is this:
std::cout << f.substr(0,i)<<std::endl;