I want to copy content of a text file (description.txt) and paste it on another text file at a particular line (movie.txt) using c++.
Here's the file contents:
description.txt
Chris Gardner takes up an unpaid internship in a brokerage firm after he loses his life's earnings selling a product he invested in. His wife leaves him and he is left with the custody of his son.
movie.txt
Movie name: The Pursuit of Happyness
Movie Description:
// description.txt content here
Initial release: November 2006
Director: Gabriele Muccino
Adapted from: The Pursuit of Happyness
I make a function that you can use.
void CopyContentOfTextFile(char* sourceFile, char* targetFile, int targetLine)
{
FILE* resultFilePtr = fopen("result.txt", "w");
FILE* sourceFilePtr = fopen(sourceFile, "r");
FILE* targetFilePtr = fopen(targetFile, "r");
char line[256];
int lineCounter= 0;
while (fgets(line, 256, targetFilePtr)!=NULL)
{
if (lineCounter == targetLine-1)
{
char lineToBeAdded[256];
//Now read sourceFile
while (fgets(lineToBeAdded, 256, sourceFilePtr) != NULL)
{
fprintf(resultFilePtr, "%s", lineToBeAdded);
}
fprintf(resultFilePtr, "%s", "\n");
}
fprintf(resultFilePtr, "%s", line);
lineCounter++;
}
fclose(sourceFilePtr);
fclose(targetFilePtr);
fclose(resultFilePtr);
//Remove old movie.txt file with new one
remove(targetFile);
rename("result.txt", targetFile);
}
To call it use something like:
int main()
{
char pathToSourceFile[] = "description.txt";
char pathToTargetFile[] = "movie.txt";
int line = 3;
CopyContentOfTextFile(pathToSourceFile, pathToTargetFile, line);
}
Related
In my file let's assume it has the following content:
my_file.txt
/* My file "\n". */
Hello World
If I wanted generate a file and pass this same content as a string in C code, the new file would look like this:
my_generated_c_file.c
const char my_file_as_string[] = "/* My file \"\\n\". */\nHello World\n\n";
In an unfortunate attempt, I tried to simply add the chars one by one:
#include <stdio.h>
int main ()
{
FILE *fp_in = fopen("my_file.txt", "r");
FILE *fp_out = fopen("my_generated_c_file.c", "w");
fseek(fp_in, 0L, SEEK_END);
long size = ftell(fp_in);
fseek(fp_in, 0L, SEEK_SET);
fprintf(fp_out, "const char my_file_as_string[] = \"");
while (size--) {
fprintf(fp_out, "%c", getc(fp_in));
}
fprintf(fp_out, \";\n\n");
fclose(fp_in);
fclose(fp_out);
return 0;
}
But that doesn't work because a '\n' for example is read as a line break and not "\\n".
How to solve this?
You could simply print a '\\' wherever a '\' was present in the original file:
while (size--) {
char next_c = getc(fp_in);
if(next_c == '\\') {
fputs("\\\\", fp_out);
}
else {
fputc(next_c, fp_out);
}
}
You'll probably also want to perform other such transformations as well, such as replacing line breaks with \n.
I am starter and right now I am trying to extract the key information from a .xml file then load them to an object of my class, for example:
Here are some information in .xml file:
<row Id="17" Phone="12468" Address="Bos" />
<row Id="242" Phone="98324" Address="Chi" Age="30"/>
<row Id="157" Phone="23268" Age="25" />
<row Id="925" Phone="54325" Address="LA" />
And my class would be:
class worker{
string ID;
string Phone;
string Address;
string Age;
}
I know the infomation would be various and if there is not that infomation of that line, we put ""(empty string) in it as return. And I know the infomation are given in the same order of the fields in class. I try to implement a function, let says extractInfo(const string& line, const string &key)
//#line: the whole line read from .xml
//#key: it would be "Id:"", "Phone:"", "Address:"" or "Age:"", so that I could reach the
// previous index of the infomation that I could extract.
extractInfo(const string& line, const string &key){
int index = line.find(key);
if(index == -1) return "";
int start = index + key.length(); //to reach the start quote
int end = start;
while(line[end] != '"'){ //to reach the end quote
end++;
}
return line.substr(start, end - start);
}
int main(){
...// for each line read from .xml, I build a new object of class worker and filling the field
worker.Id = extraInfo(line, "Id:\"");
worker.Phone = extraInfo(line, "Phone:\"");
...//etc.
...//then work on other manipulation
return 0;
}
My question are, is there any way that I could read and load the infomation from xml much more quickly through other APL or functions? That is, is there any way for me to improve this function when the .xml is a huge file with TBytes? And, is there any way that I can use less memory to, for example, find the oldest worker then print out? I know it's tough for me and I still try hard on it!
Thank all the ideas and advice in advance!
You can parse XML with existing XML parsing libraries, such as rapidxml, libxml2, etc.
Please note that for huge XML, since it need read all XML content to create the DOM tree, so the DOM method is not really suitable. you can use libxml2's xmlreader to parse each node one by one.
libxml2 xml reader
static void
streamFile(const char *filename) {
xmlTextReaderPtr reader;
int ret;
reader = xmlReaderForFile(filename, NULL, 0);
if (reader != NULL) {
ret = xmlTextReaderRead(reader);
while (ret == 1) {
const xmlChar *name = xmlTextReaderConstName(reader);
if(xmlStrEqual(BAD_CAST "row", name)) {
const xmlChar *id = xmlTextReaderGetAttribute(reader, "Id");
const xmlChar *phone = xmlTextReaderGetAttribute(reader, "Phone");
// you code here...
xmlFree(id);
xmlFree(phone);
}
ret = xmlTextReaderRead(reader);
}
xmlFreeTextReader(reader);
if (ret != 0) {
fprintf(stderr, "%s : failed to parse\n", filename);
}
} else {
fprintf(stderr, "Unable to open %s\n", filename);
}
}
And, If your XML format is always like above, you can also use std::regex_search to handle it
https://en.cppreference.com/w/cpp/regex/regex_search
#include <iostream>
#include <string>
#include <regex>
int main()
{
std::string str = R"(<row Id="17" Phone="12468" Address="Bos" />)";
std::regex regex("(\\w+)=\"(\\w+)\"");
// get all tokens
std::smatch result;
while (std::regex_search(str, result, regex))
{
std::cout << result[1] << ": " << result[2] << std::endl;
str = result.suffix().str();
}
}
I made a phonebook program which includes Add and search a contact.
But when I made the delete function, it deleted all the contacts instead of the one I entered.
I know it's a little bit complicated but any ideas?
This is the input in phonebook.txt from which I want to delete a contact:
Barney Hackett 0114543053
Luis Avery 01056633489
Hudson Ramsay 01576633982
Ihe code is:
void DeletePhoneNumber() {
FILE* search, * fp1;
//to receive the enter from system("cls")
char temp;
scanf("%c", &temp);
search = fopen("PHONEBOOK.txt", "r+");
fp1 = fopen("temp.txt", "w");
system("cls");
printf("\t*****DELETE CONTACT*****");
printf("\n\t Enter Name: ");
int length;
length = strlen(SearchName);
int i, y = 0;
//string comparison//
while (fgets(name, 50, search) != NULL) {
fputs(name, fp1);
}
fclose(search);
fclose(fp1);
search = fopen("PHONEBOOK.txt", "w");
fp1 = fopen("temp.txt", "r");
while (fgets(name, 50, search) != NULL) {
fputs(name, search);
}
fclose(search);
fclose(fp1);
remove("temp.txt");
printf("\n\tPRESS ANY KEY TO CONTINUE");
getch();
MainMenu();
}
}
I'll use this "answer" space to give you a partial analysis of your code. You can use it to improve your code.
Basically, your loop is all wrong:
search = fopen("PHONEBOOK.txt", "r+");
while (fgets(name, 50, search) != NULL) {
// ...
while (token != NULL) {
// ...
fclose(search);
search = fopen("PHONEBOOK.txt", "w");
You opened the file in append mode, read from it and now close the file, to open it in a different mode. What will it read on the next fgets in the while loop?
Opening the file in mode "w" for writing will destroy the file. So here is why there are no more entries in your file.
fclose(search);
MainMenu();
At the bottom of the loop you close the file. How can it still read something with fgets in the while loop.
Next you call MainMenu. But I assume this function calls this DeletePhoneNumber function, so you are in a strange loop/recursion. Of course, when you are done with deleting the phone number, you simply return to the main menu, not call it again.
I'm having an issue with libexif saving tags string data. I'm allocating memory for string value, using strcpy and then just assiggn pointer to specific tags entry->data. Problem is - saving with exif_data_save_data and fwrite, i get my string value cutted to 7 chars. If I load all this data at first from file with longer string value for this specific exif tag (EXIF_TAG_NAME in particular), max string len coud be different.
static char* get_c_str(QString qs)
{
QByteArray *qba = new QByteArray(qs.toLatin1());
char* str = (char *)malloc(qba->count());
strcpy(str,qba->data());
return str;
}
static ExifEntry *init_tag(ExifData *exif, ExifIfd ifd, ExifTag tag)
{
ExifEntry *entry;
if (!((entry = exif_content_get_entry (exif->ifd[ifd], tag)))) {
entry = exif_entry_new ();
assert(entry != NULL);
entry->tag = tag;
exif_content_add_entry (exif->ifd[ifd], entry);
exif_entry_initialize (entry, tag);
exif_entry_unref(entry);
}
return entry;
}
void MainWindow::on_writeButton_clicked()
{
if(!buf)
return;
ent = init_tag(ed,ExifIfd::EXIF_IFD_0,ExifTag::EXIF_TAG_MODEL);
ent->data = (unsigned char*)get_c_str(ui->modelL->text());
................................................
exif_data_save_data(ed, &exifData, &exifDatLen);
f = fopen(path, "wb");
fwrite(exif_header,exif_header_len,1,f);
fputc((exifDatLen+2)>>8,f);
fputc((exifDatLen+2) & 0xff, f);
fwrite(exifData,exifDatLen,1,f);
fwrite(buf+image_data_offset,flen,1,f);
fclose(f);
}
Expected Camera Model to be "Canon EOS 5D Mark II" but was "Canon E"
I am trying to write song information to a text file but nothing is being written to it. The part where I am trying to write the information to onF is running but the file is blank. BTW the code below is part of a recursive function which is the reason for the first few if statements. Any ideas?
void writeToFile(int artist, int album, int song, int nA, int nAl, int nS)
{
ofstream onF("library.txt");
if(song>=nS)
{
album+=1;
song = 0;
}
if(album>=nAl)
{
artist++;
album = 0;
song = 0;
}
if(artist>=nA)
{
onF.close();
return;
}
if(onF.is_open())
{
onF<<artists[artist].artistName<<'#';
onF<<artists[artist].albums[album].albumName<<'#';
onF<<artists[artist].albums[album].songs[song].songName<<'#';
onF<<artists[artist].albums[album].songs[song].songLength<<endl;
cout<<"RAN"<<endl;
}
else
cout<<"File could not be opened."<<endl;
song++;
int numAlbums = artists[artist].numAlbums;
int numSongs = artists[artist].albums[album].numSongs;
writeToFile(artist, album, song, nA, numAlbums, numSongs);
}
Now that I have that working I am having trouble loading the information from the file. It's loading the song info twice with the second time loading everything but the song title. The loop runs twice:
if(inF)
{
while(!inF.eof())
{
getline(inF, newArtist, '#');
getline(inF, newAlbum, '#');
getline(inF, newSong, '#');
inF>>songLength;
cout<<"CALLED"<<endl;
addSong(newArtist, newAlbum, newSong, songLength, numArtists, 0, 0);
}
inF.close();
if(inF.is_open())
cout<<"FAILED TO CLOSE"<<endl;
}
You're truncating the file on entry to the function, so the last call will erase all that has been written.
If you want to append, add the std::ios::app flag