C++ Program for Renaming Multiple Files at Once - c++

I have a directory full of JPG files named Slide1, Slide2, Slide3, etc and I want to rename them to a list of names I wrote in a txt file titled "names.txt". Each new name is on one line, so basically I need to read this txt file line-by-line and make each line the new name of a JPG file. I will need to do this for multiple directories, but I expect each one to only contain a max of 60 JPGs (I will use the same names.txt file to rename the JPGs in each directory because it does not matter if there are duplicate JPG names between the directories, it only matters that the no two JPGs in the same directory have the same name).
This is the code I have so far. I know one problem is that char oldname[] and char newname[] can't use the + operator. So how do I get char oldname[] for each JPG to be Slide1, Slide2, etc? As for char newname[], I thought maybe I need to read each line of names.txt as a string and then convert that string to char and set it as char newname[] but I don't know how to do that.
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
int myNum;
cout << "How many slides are there? Max 60." << endl;
cin >> myNum;
if (myNum > 60)
cout << "Add more names to names.txt in lyrics folder, then rerun program." << endl;
if (myNum <= 60)
{
int nextNum = 1;
fstream readname;
readname.open("names.txt",ios::in);
if (readname.is_open())
{
string line;
while (getline(readname,line))
{
char oldname[] = "Slide" + nextNum + ".JPG";
char newname[] = line + ".JPG";
nextNum = nextNum++;
if (nextNum == myNum+1)
break;
}
readname.close();
}
}
return 0;
}
If anyone can explain how to do this using string instead of char, that would be fine too. This isn't an assignment, it's just a personal project, so there are no limits to what methods I can use.

From C++11 we have a function std::to_string this takes a numeric value and returns a std::string object. More info at https://en.cppreference.com/w/cpp/string/basic_string/to_string
Using that you can convert your code(in while loop) as follows:
std::string oldName = std::string("Slide") + std::to_string(nextNum) + ".JPG";
std::string newName = line + ".JPG";
Hope this helps,
Thanks

You should not be using char[] arrays at all. Just use std::string instead:
std::string oldname = "Slide" + std::to_string(nextNum) + ".JPG";
// Or, if you are not using C++11 or later:
/*
std::ostringstream oss;
oss << "Slide" << nextNum << ".JPG";
std::string oldname = oss.str();
*/
string newname = line + ".JPG";

Related

how to properly use fstream and passing data in a char array?

In this function what I have to do is pass the strings from txt file in char and do some operations. My only problem is on pass file from txt to char. how i should fix it?
char* foo(string& input){
stringstream ss;
ss<<input;
char *elements=new char[32];
elements[32]='\0';
ss>>elements; //next part code not written because useless
This is how you can store data in a char array from a file:
Source File
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream inFile;
inFile.open("Input File.txt");
char Array[50] = { ' ' };
inFile.get(Array, 50);
cout << "Output : " << Array << endl;
inFile.close();
}
Text File
Enter Text Here
If you want i can make a dynamic array for you which will have the exact size as the string (Data you input) from file or use vectors because they can easily be expanded and shortened in late binding(means: during program execution).

Trying to return size of input file of c++ but recieve an error when I convert the char variable to string

I am trying to count the characters in my program. Initially my variable "words" was a char and the file read just fine. When trying to determine the length of the variable, it wouldn't work with .length(). Can you explain how I can make my "words" variable as a string so that the words.length() executes correctly?
error on line words = readFile.get(); is:
no match for ‘operator!=’ in ‘words != -0x00000000000000001’
#include <iostream>
#include <cmath>
#include <fstream>
#include <cstdlib>
#include <string>
#include <stdio.h>
#include <math.h>
using namespace std;
int main() {
//buff array to hold char words in the input text file
string words;
//char words;
//read file
ifstream readFile("TextFile1.txt");
//notify user if the file didn't transfer into the system
if (!readFile)
cout <<"I am sorry but we could not process your file."<<endl;
//read and output the file
while (readFile)
{
words = readFile.get();
if(words!= EOF)
cout <<words;
}
cout << "The size of the file is: " << words.length() << " bytes. \n";
return 0;
}
char c;
while (readFile.get(c))
{
words.insert(c);
}
Of course, if you were solely doing this to count the number of characters (and were intent on using std::istream::get) you'd probably be better off just doing this:
int NumChars = 0;
while (readFile.get())
{
NumChars++;
}
Oh, and by the way, you might want to close the file after you're done with it.
You should read some reference.. try cppreference.com and look for std::instream::get
I'm not sure what do you want, but if you wanna just count words, you can do something like this:
std::ifstream InFile(/*filename*/);
if(!InFile)
// file not found
std::string s;
int numWords = 0;
while(InFile >> s)
numWords++;
std::cout << numWords;
Or if you want to get to know how many characters are in file, change std::string s to char s and use std::ifstream::get instead:
std::ifstream InFile(/*filename*/);
if(!InFile)
// file not found
char s;
int numCharacters = 0;
while(InFile.get(s)) //this will read one character after another until EOF
numCharacters++;
std::cout << numCharacters;
The second approach is easier:
If file uses ASCII, numCharacters == fileSize;
Otherwise if it uses UNICODE, numCharacters == fileSize / 2;
get() returns an int, to do what you're doing, you must check that int before appending to "words" instead of checking words against EOF, e.g.:
...
//read and output the file
while (readFile)
{
const int w = readFile.get();
if (w!= EOF) {
words += w;
cout <<words;
}
}
...

How to replace value in CSV file

I have CSV file build like this:
1;name;2;5;
2;diff_name;3;5;
And I would like to be able to replace the 5 with 2 before reading the next line.
So I am reading the file:
file>>number1;
file.ignore( numeric_limits < streamsize >::max(), ';' );
file>>data;
and so on. And I was trying to write it this way:
long pos = plik.tellp();
plik.seekp (pos-2);
plik<<other_number;
But it breaks the file. I don't know how but it's not reliable. the pos somehow depends on the file lenght and I can't make it work every time (with different valuse in file) this way. Is there some other way to replace the value here? Is there an easy way?
As said by Joachim Pileborg in a comment, you can't really (and simply) directly replace in the file. The solution is to write in an other file. If your first file is enough small, you can use your memory in place of a second file, and write the result in the first file.
My code :
#include <fstream>
#include <iostream>
using namespace std;
int main(){
ifstream ifile("file.csv"); //First file
ofstream ofile("filenew.csv"); //File with replaced fields
char s[100];
string temp;//useful for the replacement
int count=0;//fields counter (useful for replacement)
while(ifile.good()){
ifile.getline(s, 100, ';'); //We read the file field by field
count++;
if(ifile.good()){
if(count==3){ //The third field is stored in a temp variable
temp = s;
}
else if(count==4){//And we put the fourth field before the third
ofile << s;
ofile << ';';
ofile << temp;
ofile << ';';
count=0;
}
else{
if(count==5)count=0;
ofile << s;
ofile << ';';
}
}
}
}

Making a sequential list of files

I have been stuck on a problem for a while now and can't seem to find an answer.
I'm trying to create multiple files with the same name but a different number at the end each time, I have attempted this at first just by using
int seq_number = 1;
while (seq_number < 10)
{
ofstream fsave;
fsave.open("filename" + seq_number + ".txt");
fsave << "blablabla";
fsave.close();
seq_number = seq_number + 1;
}
But that gives me a very strange result where the letters get jumbled up, I'm not sure how that works but I know it doesn't.
I've looked online and found stringstream or sstream, and tried with that, but it keeps giving me errors too,
string filename;
filename = "character";
ostringstream s;
s << filename << seq_number;
filename(s.str());
fsave.open(filename + ".txt");
fsave << "blabla"
fsave.close(;)
but i keep getting an error:
no match for call to `(std::string) (std::basic_string, std::allocator >)'
I'm not sure how string stream works exactly so im working off of instinct, but i would appreciate any way this is possible, and honestly I think I would prefer doing it without sstream, but i need a way to get an int and str together and save a filename that is a string.
unless you know a better way ;) thanks guys
filename(s.str());
this is wrong; you are not constructing a new variable (filename is already constructed), what you want here is an assignment.
filename = s.str();
Then,
fsave.open((filename + ".txt").c_str());
(although, if you are using C++11, this change is not necessary)
Still, personally I would just construct the whole file name with the stream:
ostringstream s;
s<<"character"<<seq_number<<".txt";
fsave.open(s.str.c_str());
I'm not sure how string stream works exactly so im working off of instinct
This is a very bad idea, C++ is often quite a minefield of bizarre syntax, segfaults and undefined behavior, going by instinct usually leads to disaster.
About the errors you get:
fsave.open("filename" + seq_number + ".txt");
This shouldn't even compile, since you are summing an integer to a const char * (thus moving the "start of the string"), and then summing it again to a const char *, which is not allowed at all. Maybe it could compile if it were like this:
fsave.open("filename" + seq_number);
but it won't give the required result - "filename" is a pointer (not a C++ string), so summing an integer to it just moves the pointer of the given offset.
In your second snippet, instead, you are using an object (filename) as it were a function, which is only allowed if the class overloads operator(); thus, the compiler complains that such an operation is not allowed on that object.
Replace
fsave.open(filename + ".txt");
With
fsave.open( (filename + ".txt").c_str() );
This is because the ofstream constructor takes as parameter a char const *, not an std::string.
Also, your first version generates strange file names because in C and C++, adding an integer to a char * simply offsets within the character array. It does not append to the string.
In C++ you can not convert an int to a string, or concatenate it to one -- not to a ´char*`:
"filename" + seq_number + ".txt"
^const char* ^int ^const char*
Also, ostream can not recieve the filename as a string, it must be a const char*, which you can acquire temporarily via ´c_str()`.
Use sprintf, ostringstream (as you did), or C++11 to_string to do that:
#include <string>
#include <iostream>
int main() {
for(int seq_number = 1; i<10; ++i) {
std::string num_as_string = std::to_string(seq_number); // make a string, C++11
std::string filename = "abcd" + num_as_string + ".txt";
std::ostream f(filename.c_str());
f << "text\n";
}
}
This (modulo typos) should get you started.
You can do it like this:
ostringstream s;
s << "character" << seq_number << ".txt";
fsave.open(s.str());
fsave << "blabla";
fsave.close();
And this is how you could implement the original loop:
for (int seq_number = 1; seq_number<10; ++seq_number)
{
ostringstream s;
s << "filename" << seq_number << ".txt";
ofstream fsave(s.str());
fsave << "blablabla";
}
You could do something like this:
#include <iostream>
#include <string>
#include <sstream>
int main (int argc, char const* argv[])
{
std::string filename;
int seq_number = 10;
filename = "character";
std::stringstream s;
s << filename << seq_number << ".txt";
filename = s.str();
std::cout<< filename << std::endl; // <-- Here open your file instead print the filename
}

how can i close files after open them in a function in c++

I work on using extensible hash to find the query FASTER.
my code is this steps:
1)read the main text file ( hudge file 4 GiB)
the file is some thing like this :
12435 alex romero
13452 jack robert
13485 marya car
45132 gun tribble
...
the user want to know that for example the key 12435 is related to what ?(answer:alex romero)
2)create a hash table for the keys in the file (i means 12435,13452,13485,...)
and i save this tables dynamically in hard disk in some text files named:0.txt,1.txt,2.txt and ....
3)when the user get query to the program then the program must calculate the hash function on its value and find the file that must be read then it is faster to find the result.
i have a function:
#define LIMIT 7
void writeInFile(int key , const char* charPos ){
int remainder = key%(LIMIT*LIMIT);
string myFileName;
ostringstream convert;
convert << remainder ;
myFileName = convert.str();
myFileName += ".txt";
FILE *my_file;
my_file = fopen(myFileName.c_str() ,"a");
fputs("\n" ,my_file);
fputs(charPos , my_file);
//fclose(my_file);
}
i wondered that when i use fclose then the speed of the program will reduced !!!
then i dont use it at the end of the function but a problem that is when i use this function many times i can't close them then i cant get access to the files.
i want to create a "list" of FILEs that i can send refrence of them to the function like: FILE &* myFiles[] or FILE &** myFiles as 3th parameter that function gets...
but i see the errors .i dont know how is its syntax of this.i means some syntax like:
void writeInFile(int key , const char* charPos , FILE &*myFiles[] ) // this makes error
the other method that i think is that can i close those files that now I can't access to them ? or can i change my code that cause this ?
update:this is my full code
#include <iostream>
#include <fstream>
#include <limits>
#include <string>
#include <sstream>
#include <stdio.h>
#include <vector>
#define LIMIT 7
using namespace std;
void writeInFile(int key , const char* charPos ){
int remainder = key%(LIMIT*LIMIT);
string myFileName;
ostringstream convert;
convert << remainder ;
myFileName = convert.str();
myFileName += ".txt";
FILE *my_file;
my_file = fopen(myFileName.c_str() ,"a");
fputs("\n" ,my_file);
fputs(charPos ,my_file);
//fclose(my_file);
}
int main(){
string fileName;
cout << "hello, please inter your file destination : " ;
cin >> fileName;
ifstream myFile ;
myFile.open(fileName.c_str() ,ifstream::in |ifstream::binary);
cout << "building the hash,please wait";
string havij;//:D this is an unusable variable in this section :))
int current;
int index;
int isCout=0;
char buffer [10];
//FILE *my_file[49];
while(!myFile.eof()){
cout << isCout << endl;
isCout++;
index = myFile.tellg();
itoa(index , buffer ,10);
//cout << buffer << endl;
myFile >> current;
writeInFile(current ,buffer);
getline(myFile,havij);
}
myFile.close();
fstream test;
//for(int i =0 ; i<LIMIT*LIMIT-1 ; i++){
// fclose(my_file[i]);
//}
cout << endl << "static extensible hash structure builded please inter your query : " ;
int query;
cin >> query;
int remainder = query%(LIMIT*LIMIT);
string myFileName;
ostringstream convert;
convert << remainder ;
myFileName = convert.str();
myFileName += ".txt";
ifstream myFile2;
//myFile2 is now the files that create by program like : 12.txt ,25.txt ,....
myFile2.open(myFileName.c_str() , ifstream::in | ifstream::binary);
ifstream mainFile;
mainFile.open(fileName.c_str(), ifstream::in | ifstream::binary);
int position;
string wanted;
int tester;
while(!myFile2.eof()){
myFile2 >> position;
mainFile.seekg(position ,ios::beg);
mainFile >> tester;
if (tester == query ){
getline(mainFile ,wanted);
cout << "the result of the key " << tester << " is " << wanted << endl;
}
}
return 0;
}
Or you could do this:
void writeInFile(int key , const char* charPos , std::vector<std::ofstream> & myFiles );
I find this makes my brain hurt less.
If you don't close your file in the same context where the FILE* variable is declared, you are leaking that file descriptor. At some point you are going to run out of resources and the program will crash.
Since you are using C++ from the snippet you've shown, then you would be much better off using std::vector and std::ofstream.
void writeInFile(int key, const char* charPos, std::vector<std::ofstream> my_files )
As has been said, you should close the file in the scope it is opened. This is the default behavior for C++ streams.
However it does not mean that you should open/close for each word you add! The files you write to should be kept open as long as you have things to add to them (beware there is a limit in the number of file descriptors an OS can handle).
Therefore, you should have:
Open all destination files (*)
For each line, select the appropriate file in a table/map and write into it
Close all destination files
(*) As said, you might run into a hard limit, in this case there is not much you can do, caching is unlikely to be effective if your hash function is worth anything. A possibility would be to make several runs over the big file and saving only a portion of the hashes at each run (say run 1: hashes in [0-9], run 2: hashes in [10-19], ...).
The fundamental type FILE* or ofstream that you use is of little importance, both have comparable speed (correctly tuned).