My program use a small SQLite3 database. To make sure it actually exist when the program is launched, I have a database creation script in a file, that is executed.
The script work without problem.
However, when using C++ I/O functions to read from that file, I am getting really often invalid characters at the end of my file, which result in the script containing errors and not being properly executed by the SQLite library. Here is an example when displaying the buffer content:
// Proper content from the file, then a random character is there
1
Error executing request: near "1": syntax error
Other characters also appear, whitespaces, numbers, letters...
Here is the code where I load my script :
std::cerr << "Creating database if needed...\n";
char sql_script[] = "/path/to/script.sql";
int script_length;
bool result = false;
std::ifstream script_fs(sql_script, std::fstream::binary | std::fstream::in);
if (script_fs) {
char* buffer;
char** err_msg = NULL;
script_fs.seekg(0, script_fs.end);
script_length = script_fs.tellg();
script_fs.seekg(0, script_fs.beg);
buffer = new char[script_length];
script_fs.read(buffer, script_length);
std::cout << "sql:\n" << buffer << "\n";
if (sqlite3_exec(m_db, buffer, NULL, NULL, err_msg) == SQLITE_OK){
result = true;
} else {
std::cerr << "Error executing: " << sqlite3_errmsg(m_db) << "\n" << err_msg << "\n";
}
delete buffer;
script_fs.close();
} else {
std::cerr << "Error opening script: " << strerror(errno) << "\n";
}
return result;
}
Why is this happening and how can I fix this ?
You need to make sure that you have a null-terminated string.
Allocate memory for one more character.
Assign the null character to the last element of buffer.
buffer = new char[script_length+1];
script_fs.read(buffer, script_length);
buffer[script_length] = '\0';
Also, use the array form of delete.
delete [] buffer;
Don't mix C and C++, If you want to read sql query file in C++ using ifstream then below code in C++ can be one approach in which you don't need to manage memory, take care of things like allocating one extra char of '\0' etc. :
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int main() {
ifstream fin("test.sql", std::fstream::binary | std::fstream::in);
std::string sqlquery = std::string(std::istreambuf_iterator<char>(fin), std::istreambuf_iterator<char>());
std::cout<<sqlquery<<std::endl;
return 0;
}
Related
I have been playing around with the fstream class in C++ to see if I am able to write some data to a text file(.txt). According to what I know, If the program tries to write to a file that does not exist then it would automatically create that file, am I wrong? This program is very simple and does not give me any compiler errors which means it builds fine. However for some reason it crashes when I run it.
Here is my code:
#include <iostream>
#include <string>
#include <stdlib.h>
#include <fstream>
std::fstream* myFile;
int main()
{
int age = 15;
std::string myName = "Javier Martinez";
std::string friendsName = "David Lyn";
//Backslash is a special character, use double backslash or forward slash instead.
myFile->open("C:/Users/NIKE/Desktop/data.txt");
if (myFile->fail())
{
std::cerr << "File was unable to be opened.";
}
*myFile << age << "\n";
*myFile << myName << "\n";
*myFile << friendsName << "\n";
myFile->close();
std::cout << "File was successfully written to with the data";
return 0;
}
Any help is appreciated. Thank you in advance.
NOTE: I am using the GNU GCC compiler with Code::Blocks IDE
myFile is uninitialized. Check it.( Allocate memory) or simply use fstream.
Your problem stems from the line:
std::fstream* myFile;
You only declared a pointer to a stream object, which is initialized to nullptr by reason of it being in the global scope. The fact that you tried accessing a non-existent object (invalid) through it, you invoked what is known as Undefined Behavior.
You do not need to allocate stream objects on the heap, rather, do:
std::fstream myFile;
On a side Note: Check your program control flow:
if (!myFile)
{
std::cerr << "File was unable to be opened.";
}
else{
myFile << age << "\n";
myFile << myName << "\n";
myFile << friendsName << "\n";
}
I am new at C/C++,
So basically I want to call an .exe file that displays 2 numbers and be able to grab those two numbers to use them in my code.
To call the .exe file I've used the system command, but I am still not able to grab those two numbers that are displayed by the .exe file
char *files = "MyPath\file.exe";
system (files);
I think this is better aproach:
Here you just create new process, and you read data that process gives you. I tested this on OS X 10.11 with .sh file and works like a charm. I think that this would probably work on Windows also.
FILE *fp = popen("path to exe","r");
if (fp == NULL)
{
std::cout << "Popen is null" << std::endl;
}else
{
char buff[100];
while ( fgets( buff, sizeof(buff), fp ) != NULL )
{
std::cout << buff;
}
}
You need to escapr back slashes in C++ string literals so:
// note the double "\\"
char* files = "MyPath\\file.exe";
Or just use forward slashes:
char* files = "MyPath/file.exe";
Its not very efficient but one thing you can to with std::system is redirect the output to a file and then read the file:
#include <cstdlib>
#include <fstream>
#include <iostream>
int main()
{
// redirect > the output to a file called output.txt
if(std::system("MyPath\\file.exe > output.txt") != 0)
{
std::cerr << "ERROR: calling system\n";
return 1; // error code
}
// open a file to the output data
std::ifstream ifs("output.txt");
if(!ifs.is_open())
{
std::cerr << "ERROR: opening output file\n";
return 1; // error code
}
int num1, num2;
if(!(ifs >> num1 >> num2))
{
std::cerr << "ERROR: reading numbers\n";
return 1; // error code
}
// do something with the numbers here
std::cout << "num1: " << num1 << '\n';
std::cout << "num2: " << num2 << '\n';
}
NOTE: (thnx #VermillionAzure)
Note that system doesn't always work everywhere because unicorn
environments. Also, shells can differ from each other, like cmd.exe
and bash. – VermillionAzure
When using std::system the results are platform dependant and not all shells will have redirection or use the same syntax or even exist!
I'm working on what will be a pretty large and complicated system and trying to make sure it's as watertight as possible right from the start. Whilst running some memory checks, I noticed something odd when using stringstreams: they don't always seem to release all the memory when they get deleted/go out of scope.
I've tried searching the internet for answers, but most are old (so possibly out of date) and/or are more concerned with refreshing the contents than releasing the memory, so I've not really been able to tell if it's a known issue or a common mistake I'm making.
I've written a simple test to show what's going on:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
using namespace std;
float getMemUsage(int& pid)
{
if (pid < 0)
pid = getpid();
char buf[30];
snprintf(buf, 30, "/proc/%u/statm", (unsigned)pid);
FILE* pf = fopen(buf, "r");
if (pf)
{
unsigned size; // total program size
//unsigned resident;// resident set size
//unsigned share;// shared pages
//unsigned text;// text (code)
//unsigned lib;// library
//unsigned data;// data/stack
//unsigned dt;// dirty pages (unused in Linux 2.6)
fscanf(pf, "%u" /* %u %u %u %u %u"*/, &size/*, &resident, &share, &text, &lib, &data*/);
fclose(pf);
return size/1024.0;
}
else
return -1.0;
}
int main(int argc, char* argv[])
{
if (argc < 2)
cerr << "no file specified\n";
ifstream file;
file.open(argv[1]);
int pid = -1;
const float memUseAtStart = getMemUsage(pid);
{
float memUseBefore = getMemUsage(pid);
stringstream sstream;
float memUseAfter = getMemUsage(pid);
cerr << "\tMemory use change after stringstream declaration: " << memUseAfter - memUseBefore << endl;
memUseBefore = getMemUsage(pid);
filebuf* pbuf = file.rdbuf();
memUseAfter = getMemUsage(pid);
cerr << "\tMemory use change after getting file buffer: " << memUseAfter - memUseBefore << endl;
memUseBefore = getMemUsage(pid);
sstream << pbuf;
memUseAfter = getMemUsage(pid);
cerr << "\tMemory use change after copying file contents: " << memUseAfter - memUseBefore << endl;
memUseBefore = getMemUsage(pid);
sstream.clear();
sstream.str( string() );
memUseAfter = getMemUsage(pid);
cerr << "\tMemory use change after 'clearing': " << memUseAfter - memUseBefore << endl;
}
cerr << "Overall memory use change: " << getMemUsage(pid) - memUseAtStart << endl;
file.close();
return 0;
}
Which gives me the following output when called with a file larger than around 32K:
Memory use change after stringstream declaration: 0
Memory use change after getting file buffer: 0
Memory use change after copying file contents: 0.0322266
Memory use change after 'clearing': 0
Overall memory use change: 0.00195312
I'm running on Linux (SL6.6) and compiling with gcc 4.1.2 (though I've also tried clang and ICC with similar results).
Obviously, it's not a huge leak; it's just a little annoying that I can't make it completely tidy... Is there something I can/should do to release the memory manually? Or is it just something weird (with my setup and/or stringstream itself) I'll have to live with?
NB The intended use for the stringstream is to read in some file contents above and then parse them line by line; I would try using istringstream but I couldn't figure out how to set its value from the ifstream...
Thanks!
The following C++ code is to read a txt file and then write the numbers of chars in each line and the number of all chars in the txt file.I use MS Visual Studio 2008.But something is wrong.Only the number of all chars is input into the txt files,but the numbers of each line are not input into the txt files.Now I cannot figure it out.Could someone give me some advice?Thanks a lot!
And my another question is what should I do to insert something in the middle of the txt file?
This is my Code:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
fstream inOut("copy.txt",ios::in | ios::out | ios::app);
if (!inOut)
{
cerr << "ERROR:cannot open file!" << endl;
return -1;
}
int cnt = 0;
char ch;
inOut.seekg(0);
while(inOut.get(ch))
{
cout.put(ch);
++cnt;
if ('\n' == ch)
{
ios::pos_type mark = inOut.tellg();
if (!inOut)
{
cerr << "ERROR!" << endl;
return -1;
}
inOut << cnt;
inOut.put(' ');
inOut.seekg(mark);
}
}
inOut.clear();
inOut << cnt << endl;
cout << "[" << cnt << "]" << endl;
}
The txt file before running:
The txt file after running:
The result in command line:
I don't know fstream's very well, but I think you want to change the way you are doing this. You can think of a file as a contiguous piece of memory. Appending on the end is easy, but inserting in the middle can be problematic. In particular, if you do insert something, then your seekg might not be valid.
I would recommend three strategies:
Understand what is going on currently (try closing file before seekg and see if anything gets written by the inOut << cnt;)
Read from one file, write to a different file -- this will most likely be more efficient and less complicated than trying to modify the file in place.
Read from source file, store and modify in memory, write out modified buffer to original file. For large files, this might be less efficient than #2, but it means you don't need two files on disk.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
fstream inOut("copy.txt",ios::in | ios::out | ios::app);
if (!inOut)
{
cerr << "ERROR:cannot open file!" << endl;
return -1;
}
int cnt = 0;
int cntline=0;
char ch;
inOut.seekg(0);
while(inOut.get(ch))
{
cout.put(ch);
//++cnt it include '\n' it should put behind of "if"
if ('\n' == ch)
{ ios::pos_type mark = inOut.tellg();
if (!inOut)
{
cerr << "ERROR!" << endl;
return -1;
}
cntline=cnt-cntline; //add it to account the number of chars of each line
inOut.seekg(0,ios::end); //here!!!!!!!!!!!!!!!!!!!!!!!!!!! add this , the resault is finally right! the reason it's down here.
inOut << cntline;
cntline=cnt; // and here! it can assure the number of the chars of each line be right!
inOut.put(' ');
inOut.seekg(mark);
}
else
{
++cnt; // it's here!
}
}
inOut.clear();
inOut << cnt << endl;
cout << "[" << cnt << "]" << endl;
}
inOut.seekg(0,ios::end)
i'am not sure it,but you can take it a reference.
you open file with "ios::app",so the VS 2008 only allows you to add text start from the end of file (it won't happened in vc 6.0).
if the file is :
it's compile by
vs 2008
when get the first '\n' the file pointer is pointing to'vs 2008'(yes,it just like the common pointer point the string ). and i debug it then find a value of the stream object named _Wrotesome .its value is false!
so i think the compiler think the file pointer point at o const sting.so you just can't write anything whis this position. so i add the code inOut.seekg(0,ios::end);.now you
can write anything you want to this text!
wish this can help you !
I don't know why do you choose std::fstream as your tool. If std::fstream is not asked or necessary, I would like to provide a example to solve your problem. Here's some limitation:
a. I read all the file into memory in one ReadFile operation. If your file is large, you may replace it with a loop.
b. I suppose your line separator is '\n'.
c. I add [line_count] before the '\n', which look like better.
here's my code.
#include "windows.h"
#include "sstream"
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hFile = ::CreateFile(L"C:\\Users\\wujian\\Desktop\\pingback - Copy.log", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE )
{
DWORD dwSize = ::GetFileSize(hFile, NULL);
if (dwSize)
{
char *pBuffer = new char[dwSize];
DWORD dwRead = 0;
::ReadFile(hFile, pBuffer, dwSize, &dwRead, NULL);
if (dwRead == dwSize)
{
std::stringstream ss;
int iPos = 0;
int iLine = 0;
while (iPos < dwSize)
{
if (pBuffer[iPos] == '\n')
{
ss << '[' << iLine << ']';
iLine = 0;
}
ss << pBuffer[iPos];
iPos ++, iLine ++;
}
ss << '[' << dwSize << ']';
::SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
DWORD dwWrite = 0;
::WriteFile(hFile, ss.str().c_str(), ss.str().length(), &dwWrite, NULL;
}
::CloseHandle(hFile);
}
}
return 0;
}
I am trying to access all files in a directory and do some thing on the files under this and the subsequent directories. For this operation I used dirent.h with windows and it manages to get all the files and open and close these files. My problem is, when i try to read some something from them and write to another, as shown below, i get the error shown at the end.
Here is the code:
#include <iostream>
#include <cstring>
#include <sys/stat.h>
#include <dirent.h>
FILE *test_file;
char buffer[51];
void listdir(const char *path)
{
struct dirent *entry;
DIR *dp;
//std::cout << "Dir: " << path << "\n";
if(dp = opendir(path))
{
struct stat buf ;
FILE *input_file;
while((entry = readdir(dp)))
{
std::string p(path);
p += "\\";
p += entry->d_name;
char fpath[250];
//strcpy(fpath,path);
if(!stat(p.c_str(), &buf))
{
if(S_ISREG(buf.st_mode))
{
std::cout << " File: " << entry->d_name << "\n";
sprintf(fpath,"%s\\%s",path,entry->d_name);
input_file=fopen(fpath,"r+b");
test_file=fopen("test_test.txt","a+b");
if(input_file==NULL)
{
std::cout<<"\n Could not open\n"<<entry->d_name<<std::endl;
continue;
}
if(test_file==NULL)
goto z;
else
{
std::cout<<"\n Successfully Opened\n"<<fpath;
fread(buffer,50,1,input_file);
fprintf(test_file,"\n\n%s\n\n",fpath);
fwrite(buffer,50,1,test_file);
fclose(input_file);
fclose(test_file);
// free(buffer);
}
z:
if(test_file=NULL)
fclose(test_file);
}
if(S_ISDIR(buf.st_mode) &&
// the following is to ensure we do not dive into directories "." and ".."
strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..") )
{
listdir(p.c_str());
}
}
else
std::cout << "ERROR in stat\n";
}
// delete buf;
closedir(dp);
}
else
std::cout << "ERROR in opendir\n";
fclose(test_file);
}
int main(int argc, char **argv)
{
listdir(argv[1]);
return 0;
}
It manages to open and read the first file but after the first file it will show the following error and open dbgheap.c
HEAP[direntdir.exe]: Invalid address specified to RtlValidateHeap(
002C0000, 002C5718 ) Windows has triggered a breakpoint in
direntdir.exe.
This may be due to a corruption of the heap, which indicates a bug in
direntdir.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while direntdir.exe has
focus.
The output window may have more diagnostic information.
EDIT:
corrected the errors with the buf variables.
Now i get
Debug Assertion Failed!
... Expression:(buffer!=NULL) ...
You have two variables named buf:
char* buf;
...
struct stat *buf = new struct stat;
The latter hides the first and latter is free()d, even though it was created using new, and then reused without being reallocated.
The latter is also used as an argument to fread(). Rename char* buf and possibly make it local to the function and just use a stack allocated buffer:
char fread_buffer[51];
EDIT:
char* buffer never has memory allocated for it before it used in fread() so the call to fread() could be writing anywhere in memory. Change to:
char buffer[50]; /* as only 50 bytes are read from the file */
and don't call free() on buffer if it is declared this way.
Also, to simplify things just declare buf as:
struct stat buf;
and call stat():
if(!stat(p.c_str(), &buf))
Making these two changes will remove all dynamic memory management from the code.
EDIT 2:
This if is an assignment, not an inequality check:
if(test_file=NULL)
fclose(test_file);
should be:
if(NULL != test_file)
fclose(test_file);