How to read in a file word by word in QT? - c++

As you can probably tell I am new to QT and I am attempting to import my console app's src code and headers to qt to build a GUI. I am stuck on one particular function which is supposed to load a file and read it in word by word. I know how to do this in C++, but in QT I have been at it for hours and I am not quite sure how to go about it. Along with reading in the file, I have to insert a string (or in this case type T) by using my own personal insert function (irrelevant to the question).
As of right now i am doing which I know is not working for conversion reasons etc:
template <typename T>
bool HashTable<T>::load(const char* filename)
{
QString word;
QFile inputFile(filename);
QTextStream fin(filename);
// std::ifstream iss;
QString line;
// iss.clear();
// iss.open(filename);
while (fin >> word)
{
insert(word);
}
fin.close();
return true;
}

QTextStream does (to my knowledge) not support word-by-word reading of files, it only support reading a certain number of characters (via read(qint64 maxlen)), reading entire lines (via readLine(qint64 maxlen = 0)) or a combination of the above. An example on how to do this is described in this answer.
What you might do - in order to get a list of words - is reading line-by-line, and splitting each read line with QString's split() function, using space as separator.

template <typename T>
bool HashTable<T>::load(const char* filename)
{
QFile inputFile(filename);
if(!inputFile.open(QIODevice::ReadOnly)) {
QMessageBox::information(0, "error", inputFile.errorString());
}
QTextStream fin(&inputFile);
while(!fin.atEnd()) {
QString line = in.readLine();
QStringList words = line.split(" ");
foreach(QString word, words){
insert(word);
}
}
filename.close();
return true;
}
You have to first open your file for reading. Then textstream should be read line by line. In above code I read a line and then split it to words using space (" ") as the token. Then you can read words from the QStringlist.

Related

Erase empty lines from a text file in C++

I have a text file, which may contain some empty lines. I want to open this file and look for the empty lines. If an empty line exists then, I want to delete that line. I do not want to create a temporary file for this purpose. I want to edit the same file and close it afterwards.
I have already seen a couple of posts about similar problem but none of them worked for me.
void DeleteEmptyLines(const string& FilePath)
{
//EXISTING File
std::fstream FileStream;
std::string CurrentReadLine;
if (doesFileExist(FilePath))
{
FileStream.open(FilePath, std::fstream::in | std::fstream::out | std::fstream::app);
//Read all the lines till the end of the file
while(getline(FileStream, CurrentReadLine))
{
//Check if the line is empty
if(CurrentReadLine.empty())
{
cout<<"Empty line found"<<endl;
//DELETE THIS EMPTY LINE
}
}
FileStream.clear();
FileStream.close();
}
// else --->> do nothing
}
Current File (MyFile.txt):
Line1
Line2
Line3
What I need (MyFile.txt):
Line1
Line2
Line3
PS: I am using VS2010 on windows machine.
Simple solution. Reads file into a string skipping empty lines, then overwrites the file with the contents of the string.
void DeleteEmptyLines(const std::string &FilePath)
{
std::ifstream in(FilePath);
std::string line, text;
while (std::getline(in, line))
if !(line.empty() || line.find_first_not_of(' ') == std::string::npos)
text += line + "\n"
in.close();
std::ofstream out(FilePath);
out << text;
}
EDIT: #skm The new answer you posted does not erase lines with empty spaces, as you stated.
To fix this use this condition to make sure a line is not "empty":
!(CurrentReadLine.empty() || CurrentReadLine.find_first_not_of(' ') == std::string::npos)
You can't do it in all currently used filesystems, because data is stored successively. So do 'delete' some bytes from file you have to move all subsequent bytes at that amount of bytes. And you can't open file for reading and at that moment rewrite it from beginning.
So you have 3 options:
Read all file into memory and then rewrite lines to the original
file skipping empty lines.
Read file line by line, save only
non-empty lines into memory, and then write then down to the same file.
Use temporary file, which is actually a good choice because you
don't have to have a lot of RAM and file moving operation is
low-cost at most filesystems (if source and destination are at the
same partition).
I have modified my function as following.
void DeleteEmptyLines(const string& FilePath)
{
std::string BufferString = "";
//File
std::fstream FileStream;
std::string CurrentReadLine;
if (doesFileExist(FilePath))
{
FileStream.open(FilePath, std::fstream::in); //open the file in Input mode
//Read all the lines till the end of the file
while(getline(FileStream, CurrentReadLine))
{
//Check if the line is empty
if(!CurrentReadLine.empty())
BufferString = BufferString + CurrentReadLine + "\n";
}
if(DEBUG) cout<<BufferString<<endl;
FileStream.close();
FileStream.open(FilePath, std::fstream::out); //open file in Output mode. This line will delete all data inside the file.
FileStream << BufferString;
FileStream.close();
}
// else --->> do nothing
}
This function does the following steps:
Open the file in input mode
Read all the lines which are not empty
Closes the file
Open the file again in Output mode (deletes all the data inside file)
Put the string into the file
Closes the file.

QFile ignoring last newline

I'm using Qt to read a file
std::vector<QString> text;
QFile f(file);
if (f.open(QFile::ReadWrite | QFile::Text) == false)
throw my_exception();
QTextStream in(&f);
QString line;
while(!in.atEnd()) {
line = in.readLine();
text.push_back(line);
}
f.close();
the problem with this approach is: I can't read extra newlines at the end of the file.
Suppose I have the following text file
Hello world\r\n
\r\n
I'm unable to get an empty string for the last \r\n line. How can I solve this?
According to http://doc.qt.io/qt-4.8/qtextstream.html#readLine \r\n are always getting trimmed. So you will miss them in every read line. You could:
a) Add line terminators to the read strings after having used readLine()
b) Use QFiles.readLine() to read into a QByteArray which doesn't touch the read bytes:
while (!f.atEnd()) {
QByteArray line = f.readLine();
process_line(line);
}
c) Use another approach for reading the file, e.g. std::istream. See http://www.cplusplus.com/reference/istream/istream/getline/ for the equivalent getline.
I think the newlines will be stripped. See Qt documentation of QTextStream.
You have to use readAll() or if newline is empty add '\n\r' by yourself.

Replace line in txt file c++

I just wondering cause i have a text file containing STATUS:USERID:PASSWORD in accounts.txt
example it would look like this:
OPEN:bob:askmehere:
OPEN:john:askmethere:
LOCK:rob:robmypurse:
i have a user input in my main as such user can login 3x else status will change from OPEN to LOCK
example after 3 tries of john
before:
OPEN:bob:askmehere:
OPEN:john:askmethere:
LOCK:rob:robmypurse:
after:
OPEN:bob:askmehere:
LOCK:john:askmethere:
LOCK:rob:robmypurse:
what i have done is:
void lockUser(Accounts& in){
// Accounts class consist 3 attributes (string userid, string pass, status)
ofstream oFile;
fstream iFile;
string openFile="accounts.txt";
string status, userid, garbage;
Accounts toupdate;
oFile.open(openFile);
iFile.open(openFile);
while(!iFile.eof()){
getline(iFile, status, ':');
getline(iFile, userid, ':');
getline(iFile, garbage, '\n');
if(userid == in.getUserId()){
toupdate.setUserId(in.getuserId());
toupdate.setPassword(in.getPassword());
toupdate.setStatus("LOCK");
break;
}
//here i should update the account.txt how do i do that?
ofile.open(openFile);
ofile<<toupdate.getStatus()<<":"<<toupdate.getUserId()":"<<toupdate.getPassword()<<":"<<endl;
}
There are two common ways to replace or otherwise modify a file. The first and the "classic" way is to read the file, line by line, check for the line(s) that needs to be modified, and write to a temporary file. When you reach the end of the input file you close it, and rename the temporary file as the input file.
The other common way is when the file is relatively small, or you have a lot of memory, is to read it all into memory, do the modification needed, and then write out the contents of the memory to the file. How to store it in memory can be different, like a vector containing lines from the file, or a vector (or other buffer) containing all characters from the file without separation.
Your implementation is flawed because you open the output file (which is the same as the input file) inside the loop. The first problem with this is that the operating system may not allow you to open a file for writing if you already have it open for reading, and as you don't check for failure from opening the files you will not know about this. Another problem is if the operating system allows it, then your call to open will truncate the existing file, causing you to loose all but the very first line.
Simple pseudo-ish code to explain
std::ifstream input_file("your_file");
std::vector<std::string> lines;
std::string input;
while (std::getline(input_file, input))
lines.push_back(input);
for (auto& line : lines)
{
if (line_needs_to_be_modified(line))
modify_line_as_needed(line);
}
input_file.close();
std::ofstream output_file("your_file");
for (auto const& line : lines)
output_file << line << '\n';
Use ReadLine and find the line you wanna replace, and use replace to replace the thing you wanna replace. For example write:
string Example = "Text to find";
openFile="C:\\accounts.txt"; // the path of the file
ReadFile(openFile, Example);
OR
#include <fstream>
#include <iostream>
#include <string>
int main() {
ifstream openFile;
string ExampleText = BOB;
openFile("accounts.txt");
openFile >> ExampleText;
openFile.replace(Example, "Hello");
}

QT: Finding and replacing text in a file

I need to find and replace some text in the text file. I've googled and found out that easiest way is to read all data from file to QStringList, find and replace exact line with text and then write all data back to my file. Is it the shortest way? Can you provide some example, please.
UPD1 my solution is:
QString autorun;
QStringList listAuto;
QFile fileAutorun("./autorun.sh");
if(fileAutorun.open(QFile::ReadWrite |QFile::Text))
{
while(!fileAutorun.atEnd())
{
autorun += fileAutorun.readLine();
}
listAuto = autorun.split("\n");
int indexAPP = listAuto.indexOf(QRegExp("*APPLICATION*",Qt::CaseSensitive,QRegExp::Wildcard)); //searching for string with *APPLICATION* wildcard
listAuto[indexAPP] = *(app); //replacing string on QString* app
autorun = "";
autorun = listAuto.join("\n"); // from QStringList to QString
fileAutorun.seek(0);
QTextStream out(&fileAutorun);
out << autorun; //writing to the same file
fileAutorun.close();
}
else
{
qDebug() << "cannot read the file!";
}
If the required change, for example is to replace the 'ou' with the american 'o' such that
"colour behaviour flavour neighbour" becomes "color behavior flavor neighbor", you could do something like this: -
QByteArray fileData;
QFile file(fileName);
file.open(stderr, QIODevice::ReadWrite); // open for read and write
fileData = file.readAll(); // read all the data into the byte array
QString text(fileData); // add to text string for easy string replace
text.replace(QString("ou"), QString("o")); // replace text in string
file.seek(0); // go to the beginning of the file
file.write(text.toUtf8()); // write the new text back to the file
file.close(); // close the file handle.
I haven't compiled this, so there may be errors in the code, but it gives you the outline and general idea of what you can do.
To complete the accepted answer, here is a tested code. It is needed to use QByteArray instead of QString.
QFile file(fileName);
file.open(QIODevice::ReadWrite);
QByteArray text = file.readAll();
text.replace(QByteArray("ou"), QByteArray("o"));
file.seek(0);
file.write(text);
file.close();
I've being used regexp with batch-file and sed.exe (from gnuWin32, http://gnuwin32.sourceforge.net/). Its good enough for replace one-single text.
btw, there is not a simple regexp syntax there. let me know If you want to get some example of script.

C++ ofstream : Always write onthe 1st line

I would like to know how could I write always to the first line of a file.
I have numbers to share via a text file to another soft, and I want to write those numbers periodically on the first line.
Thanks.
eo
If you want to completely rewrite the file, discarding it's contents then simply use trunc mode. However, if there is any other content that you want to preserve then the easiest way would be to read the file into memory, change the first line and write everything back. I think it wouldn't be possible to change the first line directly unless you are overwriting the same amount of characters.
Look at this two functions:
ostream& seekp ( streampos pos );
ostream& seekp ( streamoff off, ios_bas:seekdir dir );
maybe this solves your problem
ofstream out("foo.txt");
out << "foo";
out << "\r" << "bar";
this will leave a file with only bar in it.
2nd method:
if the file only contains one line you could open it with ofstream::trunc and close it after each write
If the file is not massive then you could write a new new file copying across each line except for the custom first line. Then afterwards replace the original.
void ReplaceFirstLine(string filename)
{
ifstream infile;
ofstream outfile;
infile.open(filename.c_str(), ios_base::in);
outfile.open("tempname.txt", ios_base::out);
bool first = true;
string s;
while (getline(infile, s, '\n'))
{
if (first)
outfile << "my new first line\n";
else
outfile << s << endl;
first = false;
}
infile.close();
outfile.close();
::CopyFileA("tempname.txt", filename.c_str(), FALSE); // or Linux equivalent
}