Writing key inputs to a file - c++

I'm compiling this code with GNU GCC Compiler in Code Blocks but for some reason the log file that it creates remains empty no matter what. Any ideas why this might be?
#include <iostream>
#include <windows.h>
#include <string>
#include <fstream>
using namespace std;
int i;
string s;
int main()
{
ofstream log;
log.open("log.txt");
while (!GetAsyncKeyState(VK_F8)) {
for (i=65; i<90; i++) {
if (GetAsyncKeyState(i)) {
s+=i;
}
Sleep(10);
}
if (GetAsyncKeyState(VK_SPACE)) {
s+=" ";
}
}
log << s;
log.close();
cin.get();
}

Consider following points:
Are you trying log << "TEST" in the condition?
Try this (right after the log.open call):
log.open("log.txt");
log << "TEST" << endl;
If TEST gets written to the file, your file is empty because the condition never gets true.
An other issue might be that the file contains non-displayable characters.
Dump your file to a hex-editor. Does the file have a size of 0 or is it containing data you might not be able to display on common text editors?
*EDIT: * This should do what you want:
Either write your i or " " directly to log or use a stringstream:
#include <sstream>
//...
ofstream log;
log.open("log.txt");
stringstream str;
while (!GetAsyncKeyState(VK_F8)) {
for (i=65; i<90; i++) {
if (GetAsyncKeyState(i)) {
str << i;
}
Sleep(10);
}
if (GetAsyncKeyState(VK_SPACE)) {
str << " ";
}
}
log << str.rdbuf();
log.close();
cin.get();

Try using if(GetKeyState(0x41)) instead for your if.

Most likely your are looking for log.txt in the wrong directory

Related

Trying to make something write to a file in c++

I tried programming a file writer, but when i try to write to a file with something that has multiple words it will suddenly create files.
My code
#include <fstream>
#include <iostream>
#include <unistd.h>
int main(int argc, char *argv[]) {
char cwd[256];
while (true) {
getcwd(cwd, 256);
std::string cwd_s = (std::string)cwd;
std::string Input;
std::cout << cwd_s << "> ";
std::cin >> Input;
std::ofstream file(Input);
std::cout << "cmd /";
std::cin >> Input;
file << Input;
};
for (int i; i < argc; i++) {
std::cout << argv[i] << '\n';
};
return 0;
}
I expected to get this:
C:\Users\code> File.txt
cmd /hello world!
File.txt
hello world!
But it only had "hello", it created another file named world!
I have tried changing the code, but to no avail.
So I have wrote this code that I think does what you expect. The behavior you were seing is because you used the same string to store the filename and the user input. Also you redefined a new file every loop (without closing the previous one). I added a signal handler since if you press Ctrl+C the program would quit without saving/closing the file.
I added comments about how you can make a better CLI interface (if you're interested)
#include <iostream>
#include <fstream>
#include <string>
#include <unistd.h>
std::ofstream outfile;
void signalHandler(int signum) {
outfile.close();
exit(signum);
}
int main() {
char cwd[256];
if (getcwd(cwd, sizeof(cwd)) != NULL) {
std::cout << cwd << "> ";
} else {
std::cerr << "Error: Could not get current working directory." << std::endl;
return 1;
}
std::string filename;
std::getline(std::cin, filename);
outfile.open(filename);
// We intercept the Ctrl+C signal to close the file before exiting. Else nothing will be written to it.
// You can also use Ctrl+D (EOF: End Of File) to exit the program.
// The best praticte would be to implement a command line interface with a "quit" command. (like a map<string, function> for example)
signal(SIGINT, signalHandler);
// Another good practice is to check if the file did open correctly.
if (!outfile.is_open()) {
std::cerr << "Error: Could not open file for writing." << std::endl;
return 1;
}
std::cout << "cmd / ";
char ch;
while (std::cin.get(ch)) {
outfile.put(ch);
if (ch == '\n') {
std::cout << "cmd / ";
}
}
outfile.close();
return 0;
}
Hope it will help you ! And if you have any question about the code feel free to ask I'll explain !

Program to read from file line by line

I've been trying to write a code to read from a file line by line:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream jin("Story.txt");
// ins.open("Story.txt", ios::in);
if (!jin)
{
cout << "File not opened" << endl;
return 1;
}
else{
char a[100];
do
{
jin.getline(a, 100);
cout << a << endl;
}
while (!jin.eof());
jin.close();
return 0;
}
}
However, on executing this program on Visual Studio Code on Windows, it behaves as infinite loop.
Can someone tell what's wrong?
(I am sure that the file Story.txt exists, no doubt about that)
When std::istream::getline has read 100-1 characters (without finding a newline,\n), it will set the failbit on the stream. This prevents further reading on the stream (unless you reset that state). It does however not set eofbit so you are now in a bit of a pickle. The failbit prevents further reading, and eof() returns false, because eofbit is not set - it will therefore loop indefinitely.
If at least one of the lines in Story.txt is longer than 99 chars, the above is what will happen.
The easiest way out is to use a std::string and std::getline instead:
#include <cerrno>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::ifstream jin("Story.txt");
if(!jin) {
std::cerr << "File not opened: " << std::strerror(errno) << std::endl;
return 1;
}
std::string a;
while(std::getline(jin, a)) {
std::cout << a << '\n';
}
return 0;
}
If you really do not want to use std::getline and std::string, you can, but it's much harder:
#include <cerrno>
#include <cstring>
#include <fstream>
#include <iostream>
int main() {
std::ifstream jin("Story.txt");
if(!jin) {
std::cerr << "File not opened: " << std::strerror(errno) << std::endl;
return 1;
}
char a[100];
while(true) {
jin.getline(a, 100);
std::cout << a; // output what we got
if(jin) {
// got a complete line, add a newline to the output
std::cout << '\n';
} else {
// did not get a newline
if(jin.eof()) break; // oh, the end of the file, break out
// reset the failbit to continue reading the long line
jin.clear();
}
}
}
jin.eof() will only return true if a eof-token is found, and this will not happend unless the file is open. That is what causing your infinite loop.
Then you would probably want something like this:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream jin{"Story.txt"};
if (!jin)
{
cout << "File not opened" << endl;
return 1;
}
for (std::string a; std::getline(jin, a);) { // Read every line
cout << a << "\n";
}
// jin is closed when going out of scope so no need for close();
return 0;
}

Cannot open text file using ifstream

ifstream fin;
fin.open("‪C:\\Users\\Zach\\Desktop\\input.txt");
if (!fin)
{
cout << "e";
}
e is printing whether I use the full pathway or just input.txt from a resource file
If the file exists, make sure that you have got the path specified correctly. Since you're running on Windows, you can verify the full path to your executable with the following code.
#include <iostream>
#include <fstream>
#include <string>
#include <windows.h>
#define BUFSIZE 4096
std::string getExePath()
{
char result[BUFSIZE];
return std::string(result, GetModuleFileName(NULL, result, BUFSIZE));
}
int main()
{
std::ifstream infile("input.txt");
if (infile.is_open())
{
std::cout << "Success!" << std::endl;
infile.close();
}
else
{
std::cout << "Failed to open input.txt!" << std::endl;
std::cout << "Executable path is ->" << getExePath() << "<-" << std::endl;
}
return 0;
}
This will allow you to verify that your path to the input file is correct, assuming that it's collocated with your executable.
You need to direct output into the ifstream object by using fin << "string"; and not directing to standard out via cout.

After convert string to const *json, when pasing json object, shows failed: (IsObject()), how to solve this?

After convert string strjson to const char* json, when interate, shows
failed: (IsObject()), function FindMember,failed, I don't understand why showed this, I think this the json object is correct format.
//
// main.cpp
// rapid
//
// Created by Shi Yan on 10/7/17.
// Copyright © 2017 Shi Yan. All rights reserved.
//
#include <iostream>
#include "rapidjson.h"
#include "document.h"
#include <fstream>
using namespace std;
using namespace rapidjson;
void readjson(){
ifstream handle("meta_Books.json");
if(handle.is_open()){
//cout<<"open success"<<endl;
const char* json;
string strjson;
int i=1;
while(getline(handle,strjson)){
if(i>4)
break;
cout<<strjson<<endl;
cout<<strjson.length()<<endl;
i++;
json=strjson.c_str();
cout<<"*********************"<<endl;
cout<<*json<<endl;
StringStream s (json);
Document document;
document.ParseStream(s);
Value::ConstMemberIterator itr = document.FindMember("asin");
cout<<itr->name.GetString()<<" = "<< itr->value.GetString()<<endl;
}
}
}
int main() {
readjson();
return 0;
}
I think the format of json object , so why failed?
As you can see , the getline() method works well, because the output of string is an complete string
The assertion error means that FindMember() is being called on a Value that does not represent a JSON object (IsObject() is false).
Since there is only 1 FindMember() in the code you showed, that implies that document.IsObject() is false when document.FindMember() fails. Either the JSON you are parsing does not start with an object in its root, or the parse failed. Neither condition of which you are testing for in your code.
If I had to guess (and please don't make people guess!), the failing JSON document likely contains an unencoded line break in it (that is not illegal inside of JSON string values). That would cause std::getline() to exit prematurely, thus causing parsing issues.
The 1st screenshot you showed supports that conclusion, showing that strjson is being split between 2 separate "lines" when the error occurs.
Rather than using std::getline() to read the file line-by-line, risking errors on embedded line breaks, I suggest you try using RapidJSON's BasicIStreamWrapper class to read the file document-by-document instead. ParseStream() has a kParseStopWhenDoneFlag flag that allows parsing multiple root documents from a single input stream:
kParseStopWhenDoneFlag 
After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error.
For example:
#include <iostream>
#include <fstream>
#include "rapidjson.h"
#include "document.h"
#include "istreamwrapper.h"
using namespace std;
using namespace rapidjson;
void readjson()
{
ifstream handle("meta_Books.json");
if (!handle.is_open())
{
// handle error...
cout << "error opening file" << endl;
}
else
{
BasicIStreamWrapper<ifstream> s(handle);
for(int i = 1; i <= 4; ++i)
{
Document document;
ParseResult pr = document.ParseStream<kParseStopWhenDoneFlag>(s);
if (!pr)
{
// handle error...
cout << "error parsing document " << i << endl;
}
else if (!document.IsObject())
{
cout << "document " << i << " is not an object" << endl;
}
else
{
Value::ConstMemberIterator itr = document.FindMember("asin");
if (itr != document.MemberEnd())
cout << "asin = " << itr->value.GetString() << endl;
else
cout << "asin not found" << endl;
}
}
}
}
int main()
{
readjson();
return 0;
}

Implement "tail -f" in C++

I want to create a small code in C++ with the same functionality as "tail-f": watch for new lines in a text file and show them in the standard output.
The idea is to have a thread that monitors the file
Is there an easy way to do it without opening and closing the file each time?
Have a look at inotify on Linux or kqueue on Mac OS.
Inotify is Linux kernel subsystem that allows you to subscribe for events on files and it will report to your application when the even happened on your file.
Just keep reading the file. If the read fails, do nothing. There's no need to repeatedly open and close it. However, you will find it much more efficient to use operating system specific features to monitor the file, should your OS provide them.
Same as in https://stackoverflow.com/a/7514051/44729 except that the code below uses getline instead of getc and doesn't skip new lines
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
using namespace std;
static int last_position=0;
// read file untill new line
// save position
int find_new_text(ifstream &infile) {
infile.seekg(0,ios::end);
int filesize = infile.tellg();
// check if the new file started
if(filesize < last_position){
last_position=0;
}
// read file from last position untill new line is found
for(int n=last_position;n<filesize;n++) {
infile.seekg( last_position,ios::beg);
char test[256];
infile.getline(test, 256);
last_position = infile.tellg();
cout << "Char: " << test <<"Last position " << last_position<< endl;
// end of file
if(filesize == last_position){
return filesize;
}
}
return 0;
}
int main() {
for(;;) {
std::ifstream infile("filename");
int current_position = find_new_text(infile);
sleep(1);
}
}
I read this in one of Perl manuals, but it is easily translated into standard C, which, in turn, can be translated to istreams.
seek FILEHANDLE,POSITION,WHENCE
Sets FILEHANDLE's position, just like the "fseek" call of
"stdio".
<...>
A WHENCE of 1 ("SEEK_CUR") is useful for not moving the file
position:
seek(TEST,0,1);
This is also useful for applications emulating "tail -f". Once
you hit EOF on your read, and then sleep for a while, you might
have to stick in a seek() to reset things. The "seek" doesn't
change the current position, but it does clear the end-of-file
condition on the handle, so that the next "<FILE>" makes Perl
try again to read something. We hope.
As far as I remember, fseek is called iostream::seekg. So you should basically do the same: seek to the end of the file, then sleep and seek again with ios_base::cur flag to update end-of-file and read some more data.
Instead of sleeping, you may use inotify, as suggested in the other answer, to sleep (block while reading from an emulated file, actually) exactly until the file is updated/closed. But that's Linux-specific, and is not standard C++.
I needed to implement this too, I just wrote a quick hack in standard C++. The hack searches for the last 0x0A (linefeed character) in a file and outputs all data following that linefeed when the last linefeed value becomes a larger value. The code is here:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int find_last_linefeed(ifstream &infile) {
infile.seekg(0,ios::end);
int filesize = infile.tellg();
for(int n=1;n<filesize;n++) {
infile.seekg(filesize-n-1,ios::beg);
char c;
infile.get(c);
if(c == 0x0A) return infile.tellg();
}
}
int main() {
int last_position=-1;
for(;;) {
ifstream infile("testfile");
int position = find_last_linefeed(infile);
if(position > last_position) {
infile.seekg(position,ios::beg);
string in;
infile >> in;
cout << in << endl;
}
last_position=position;
sleep(1);
}
}
#include <iostream>
#include <fstream>
#include <string>
#include <list>
#include <sys/stat.h>
#include <stdlib.h>
#define debug 0
class MyTail
{
private:
std::list<std::string> mLastNLine;
const int mNoOfLines;
std::ifstream mIn;
public:
explicit MyTail(int pNoOfLines):mNoOfLines(pNoOfLines) {}
const int getNoOfLines() {return mNoOfLines; }
void getLastNLines();
void printLastNLines();
void tailF(const char* filename);
};
void MyTail::getLastNLines()
{
if (debug) std::cout << "In: getLastNLines()" << std::endl;
mIn.seekg(-1,std::ios::end);
int pos=mIn.tellg();
int count = 1;
//Get file pointer to point to bottom up mNoOfLines.
for(int i=0;i<pos;i++)
{
if (mIn.get() == '\n')
if (count++ > mNoOfLines)
break;
mIn.seekg(-2,std::ios::cur);
}
//Start copying bottom mNoOfLines string into list to avoid I/O calls to print lines
std::string line;
while(getline(mIn,line)) {
int data_Size = mLastNLine.size();
if(data_Size >= mNoOfLines) {
mLastNLine.pop_front();
}
mLastNLine.push_back(line);
}
if (debug) std::cout << "Out: getLastNLines()" << std::endl;
}
void MyTail::printLastNLines()
{
for (std::list<std::string>::iterator i = mLastNLine.begin(); i != mLastNLine.end(); ++i)
std::cout << *i << std::endl;
}
void MyTail::tailF(const char* filename)
{
if (debug) std::cout << "In: TailF()" << std::endl;
int date = 0;
while (true) {
struct stat st;
stat (filename, &st);
int newdate = st.st_mtime;
if (newdate != date){
system("#cls||clear");
std::cout << "Print last " << getNoOfLines() << " Lines: \n";
mIn.open(filename);
date = newdate;
getLastNLines();
mIn.close();
printLastNLines();
}
}
if (debug) std::cout << "Out: TailF()" << std::endl;
}
int main(int argc, char **argv)
{
if(argc==1) {
std::cout << "No Extra Command Line Argument Passed Other Than Program Name\n";
return 0;
}
if(argc>=2) {
MyTail t1(10);
t1.tailF(argv[1]);
}
return 0;
}