C++/CLI - URL Download to File - c++

I'm not entirely familiar with how CLI works, but I have a general idea. I have a function that takes 2 System::String variables, and uses those to download a file from a webpage. As far as the download goes, it works fine, and the file shows up in my directory with the necessary content. However, it gives me the error
An unhandled exception of type 'System.AccessViolationException'
occurred in ParseLinks.exe
void downloadFile(System::String ^_URL, System::String ^_saveAs)
{
try
{
System::Net::WebClient ^webClient = gcnew System::Net::WebClient();
// Downloads the resource with the specified URI to a local file.
webClient->DownloadFile(_URL, _saveAs);
webClient->Dispose();
}
catch (System::Exception ^_e)
{
// Error
System::Console::WriteLine("Exception caught in process: {0}", _e);
}
}
I did some digging and output testing, and found out that the exe is hitting a break point somewhere in the text file, as the entire webpage did not save to the txt file.
Relevant code for that:
if (myFile.is_open()) //if file open
{
while (!myFile.eof()) //before end of file
{
getline(myFile, ln);
lines[count] = ln;
count++; //count total lines to set loop length for later parsing
//Error occurs somewhere in here
}
myFile.close();
}
else
cout<<"Error: Could not access file\n";
Brand New Error! :(
An unhandled exception of type 'System.Runtime.InteropServices.SEHException' occurred in ParseLinks.exe
The code after the file -> line array loop
myFile.close(); //Close txt file
//Loop through lines
for (int i = 0; i < count; i++)
{
string temp = parseLinks(lines[i]); //parse links from each line
The function for that:
string parseLinks(string str)
{
const int len = str.length();
string link;
bool quotes = false, islink = false;
string compare[5] = {".htm",".html",".php",".asp",".pdf"};
//Parse all quoted text
for (int i = 0; i != len; i++)
{
//Change bool if quote found
if (str[i] == '"')
{
if (quotes == false)
quotes = true;
else
quotes = false;
}
//If bool true, and char is not a quote, add to link string
if (quotes == true && str[i] != '"')
link += str[i];
}
//Discard non-link text
for (int i = 0; i < 5; i++)
{
//Link check for links given array of path filetypes
if (link.compare((link.length() - compare[i].length()),compare[i].length(),compare[i]) == 0)
islink = true;
}
//Link check for links with no path filetype (.html, .php, etc.)
if (link.compare(0,7,"http://") == 0)
islink = true;
//If not a link, return empty string
if (islink == false)
link = "";
return link;
}
The error points to my large compare statement in this function. (Also, I'm clearly terrible at compressing my code)

You're using getline wrong, and possibly that's causing your error. The correct idiom is this:
std::string line;
while (std::getline(myFile, line))
{
// process `line`
}
There's no need to check myFile for openness separately.

Related

Matching word c++ program using getline() running infinitely?

I am learning c++ so bear with me and apologize for any idiocy beforehand.
I am trying to write some code that matches the first word on each line in a file called "command.txt" to either "num_lines", "num_words", or "num_chars".
If the first word of the first line does not match the previously mentioned words, it reads the next line.
Once it hits a matching word (first words only!) it prints out the matching word.
Here is all of my code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
ifstream comm_in("commands.txt"); // opens file
string command_name = "hi"; // stores command from file
bool is_command() {
if (command_name == "num_words" || command_name == "num_chars" || command_name == "num_lines") {
return true;
} else {
return false;
}
}
// FIND a first word of a line in file THAT MATCHES "num_words", "num_chars" or "num_lines"
void get_command() {
string line;
char c;
while (!is_command()) { // if command_name does not match a command
// GET NEXT LINE OF FILE TO STRING
getline(comm_in, line);
// SUPPOSED TO GET THE FIRST WORD OF A STRING (CANT USE SSTREAM)
for (int i = 0; i < line.size(); i++) { // increment through line
c = line[i]; // assign c as index value of line
if (c == ' ' || c == '\t') { // if c is a space/tab
break; // end for loop
} else {
command_name += c; // concatenate c to command_name
} // if
} // for
} // while
return;
}
int main() {
get_command();
cout << command_name; // supposed to print "num_lines"
}
The contents of the command.txt file:
my bear is happy
and that it
great ha
num_lines sigh
It compiles properly, but when I run it in my terminal, nothing shows up; it doesn't seem to ever stop loading.
How can I fix this?
Unless you really want to hate yourself in the morning (so to speak) you want to get out of the habit of using global variables. You'll also almost certainly find life easier if you break get_command into (at least) two functions, one specifically to get the first word from the string containing the line.
I'd write the code more like this:
bool is_cmd(std::string const &s) {
return s == "num_words" || s == "num_chars" || s == "num_lines";
}
std::string first_word(std::istream &is) {
std::string line, ret;
if (std::getline(is, line)) {
auto start = line.find_first_not_of(" \t");
auto end = line.find_first_of(" \t", start);
ret = line.substr(start, end - start);
}
return ret;
}
void get_command(std::istream &is) {
std::string cmd;
while (!(cmd = first_word(is)).empty())
if (is_cmd(cmd)) {
std::cout << cmd;
break;
}
}
This still isn't perfect (e.g., badly formed input could still cause it to fail) but at least it's a move in what I'd say is a better direction.
If something goes wrong and you reach the end of file the loop will never stop. You should change getline(comm_in, line) to if(!getline(comm_in, line)) break;, or better yet, use that as the condition for the loop.
You also have to reset command_name for each pass:
while(getline(comm_in, line))
{
command_name = "";
for(int i = 0; i < line.size(); i++)
{
c = line[i];
if(c == ' ' || c == '\t')
break;
else
command_name += c;
}
if(is_command())
break;
}
// FIND a first word of a line in file THAT MATCHES "num_words", "num_chars" or "num_lines"
void get_command()
{
string line;
char c;
while (!is_command()) { // if command_name does not match a command
// GET NEXT LINE OF FILE TO STRING
if(getline(comm_in, line),comm_in.fail()){
// end reading
break;
}
//clear
command_name = "";
// SUPPOSED TO GET THE FIRST WORD OF A STRING (CANT USE SSTREAM)
for (int i = 0; i < line.size(); i++) { // increment through line
c = line[i]; // assign c as index value of line
if (c == ' ' || c == '\t') { // if c is a space/tab
break; // end for loop
} else {
command_name += c; // concatenate c to command_name
} // if
} // for
} // while
return;
}
The key of this problem is that you didn't clear the command_name.
What's more, you have to add a judge about whether reaching the end of the file.
ps: if(getline(comm_in, line),comm_in.fail()) is equal to if(getline(comm_in, line)),

Arduino - SD text file remove row

I build script to delete one row from SD from .txt file.
Script works well but if I use longer string TextToRemove (for example length is 9) script ignore the line and println empty line. Additionally following condition is always true.
if (buffer.substring(0, buffer.length() - 1) != TextToRemove)
Basically idea is to
Create a new file *_tmp
Read first line from original file
Compare if line is equal to TestToRemove
If text is not equal println to tmp file, if is equal igonore the line
Repeat steps 2-4.
Delete original file
Rename tmp file (remove _tmp)
boolean RemovePin(String TextToRemove, String FileName) {
String buffer;
String FileName_new = FileName + "_tmp";
File myFile;
File myFile_new;
boolean Removed = false;
char filename2[FileName.length() + 1];
FileName.toCharArray(filename2, sizeof(filename2));
myFile = SD.open(FileName);
myFile_new = SD.open(FileName + "_tmp", FILE_WRITE);
if (myFile_new) {
if (myFile) {
while (myFile.available()) {
buffer = myFile.readStringUntil('\n');
if (buffer.substring(0, buffer.length() - 1) != TextToRemove) {
myFile_new.println(buffer.substring(0, buffer.length() - 1));
} else {
Removed = true;
}
}
myFile.close();
SD.remove(filename2);
} else {
Serial.print("error opening ");
Serial.println(FileName);
}
myFile_new.rename(SD.vwd(), filename2);
myFile_new.close();
} else {
Serial.println("error opening tmp file");
}
return Removed;
}
Thank you very much for your help

Alternating between reading and writing repeatedly

My objective is to read a file line by line, check if that line contains some number, and if so rewrite that line. Then continue reading the file.
I've successfully been able to do this for one line, but I can't figure out how to continue reading the rest of the file.
Here's how I replace one line (every line is a known fixed size):
while(getline(fs, line)){
if(condition){
pos = fs.tellg(); //gets current read position (end of the line I want to change)
pos -= line.length()+1; //position of the beginning of the line
fs.clear(); //switch to write mode
fs.seekp(pos); //seek to beginning of line
fs << new_data; //overwrite old data with new data (also fixed size)
fs.close(); //Done.
continue;
}
}
How do I switch back to read and continue the getline loop?
I had the same problem, TB-scale files and I wanted to modify some header information in the beginning of the file.
Obviously one has to leave enough room when one initially creates the file for any new content, because there is no way to increase the file size (besides appending to it) and the new line has to have the exact same line length as the original one.
Here is a simplification of my code:
#include <iostream>
#include <fstream>
using namespace std;
bool CreateDummy()
{
ofstream out;
out.open("Dummy.txt");
// skip: test if open
out<<"Some Header"<<endl;
out<<"REPLACE1 12345678901234567890"<<endl;
out<<"REPLACE2 12345678901234567890"<<endl;
out<<"Now ~1 TB of data follows..."<<endl;
out.close();
return true;
}
int main()
{
CreateDummy(); // skip: test if successful
fstream inout;
inout.open("Dummy.txt", ios::in | ios::out);
// skip test if open
bool FoundFirst = false;
string FirstText = "REPLACE1";
string FirstReplacement = "Replaced first!!!";
bool FoundSecond = false;
string SecondText = "REPLACE2";
string SecondReplacement = "Replaced second!!!";
string Line;
size_t LastPos = inout.tellg();
while (getline(inout, Line)) {
if (FoundFirst == false && Line.compare(0, FirstText.size(), FirstText) == 0) {
// skip: check if Line.size() >= FirstReplacement.size()
while (FirstReplacement.size() < Line.size()) FirstReplacement += " ";
FirstReplacement += '\n';
inout.seekp(LastPos);
inout.write(FirstReplacement.c_str(), FirstReplacement.size());
FoundFirst = true;
} else if (FoundSecond == false && Line.compare(0, SecondText.size(), SecondText) == 0) {
// skip: check if Line.size() >= SecondReplacement.size()
while (SecondReplacement.size() < Line.size()) SecondReplacement += " ";
SecondReplacement += '\n';
inout.seekp(LastPos);
inout.write(SecondReplacement.c_str(), SecondReplacement.size());
FoundSecond = true;
}
if (FoundFirst == true && FoundSecond == true) break;
LastPos = inout.tellg();
}
inout.close();
return 0;
}
The input is
Some Header
REPLACE1 12345678901234567890
REPLACE2 12345678901234567890
Now ~1 TB of data follows...
The output is:
Some Header
Replaced first!!!
Replaced second!!!
Now ~1 TB of data follows...

Microsoft C++ exception: std::out_of_range error?

I keep getting the following error:
Unhandled exception at 0x74BDD8A8 in FileName.exe: Microsoft C++ exception: std::out_of_range at memory location 0x004FA55C.
I've done some searching but I was not able to solve this problem. I did narrow it down to the fact that the out of range error is coming from my string fdata variable. Here is my code where error/exception occurs:
void MyClass::MyMethod10()
{
string fdata;
char num[100];
int i = 0,k=0;
unsigned int m,j=0;
inputFile.open("sec1.txt", ios::in);
inputFile >> fdata;
while (j<fdata.length())
{
while (fdata.at(j) != '+')
{
if (fdata.at(j) != '*' && j<fdata.length())
{
num[k] = fdata.at(j);
k++;
}
else
{
num[k] = '\0';
m = atoi(num);
//cout << m << endl;
MyMethod22(m);
k = 0;
}
j++;
}
MyMethod22(43);
j++;
}
inputFile.close();
outputFile.open("sec2.txt", ios::out);
while (i<index)
{
outputFile << (char)data[i];
i++;
}
outputFile.close();
CleanBuffer();
}
The sec1.txt file contains the following data
25750*23084*57475*15982*+57475*15982*+13364*15982*26260*+48840*32397*13364*15982*57475*11371*21876*+25197*
In the while() loop section my program is able to read the data correctly from the file. The problem/error/exception occurs at the point where my program takes in the last number from the file. I am guessing the problem is in the while() loop, but I am not able to figure out what's wrong. All I was able to do was to narrow down the error to string fdata being out of range after it reads the last number from the file. I was wondering if anyone can help me to solve this or suggest something which I might have missed?
The actual problem you have is here:
while (fdata.at(j) != '+')
{
...
j++;
}
Note that you increment j, and try to read j-th character before you check if j is in range. To fix it, change it like this:
while (j < fdata.size() && fdata.at(j) != '+')
{
...
j++;
}

trying to read a config file

sorry in advance for the formatting. Couldn't figure it out...
I'm passing a config file to a program via arguments
I'm trying to read a value from a specific parameter
I've got a cofigReader class with the following method for returning a string from a config file given a specific parameter
My problem,
it never finds the parameter. found is either 0 or -1....
string configReader::value(string config_file, string parameter)
{
string value;
char config_delimiter = '=';
size_t found;
file.open(config_file);
std::string line;
bool param_found = false;
while(param_found == false){
while (!file.eof())
{
getline(file,line);
logger.writetolog("INFO","Looking for " + parameter +
" on line "+ line);
found = line.find(parameter);
logger.writetolog("INFO",int(found));
if(found!=string::npos){
param_found = true;
}
}
param_found = true;
}
if (found!=string::npos)
{
size_t a = line.find(config_delimiter)+1;
logger.writetolog("INFO","Found" + parameter +
"splitting string at delimter" + config_delimiter +
" and return right side value");
value = line.substr(a);
return value;
}
else
{
return value;
}
file.close();
}
more info. Config file reads like this.
toemail=someemailaddress#gmail.com
outputdir=C:\tmp
configReader class used like this
//attempt to parse out the required parameters for the program
string toemail = config.value(configFileArg,"toemail");
it ALWAYS return empty
Your while (!file.eof()) loop continues after you find a match, over-writing the value of found which you check later.
You could fix this by changing your loop to something like
bool param_found = false;
while (!param_found && !file.eof()) {
if (getline(file,line)) {
break;
}
logger.writetolog("INFO","Looking for " + parameter +" on line "+ line);
found = line.find(parameter);
logger.writetolog("INFO",int(found));
if(found!=string::npos){
param_found = true;
break;
}
}
instead. (Notice that this code removes your while(param_found == false) loop. As sftrabbit points out, that loop is unnecessary.)
The idiomatic way to write loop is this:
bool param_found = false;
while (std::getline(file,line)) //<-- this is idiomatic loop!
{ //successfully read OR exit from the loop
logger.writetolog("INFO","Looking for " + parameter +" on line "+ line);
found = line.find(parameter);
logger.writetolog("INFO",int(found));
if(found!=string::npos){
param_found = true;
break;
}
}
You should not use eof() when writing loops:
Why is iostream::eof inside a loop condition considered wrong?
What's preferred pattern for reading lines from a file in C++?
These two topics discuss this in detail.