copy multiple text files from a folder into different folders in C++ - c++

I have made a samll c++ program to copy multiple files from a folder to some other folders. For example: I have 2 files named 0.txt and 1.txt in a input folder and I want to copy 0.txt to a folder named 1 and 1.txt to a folder named 2 (these folders are previously made). My sample code is as follows:
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include<stdlib.h>
#include<fstream>
#include <sstream>
using namespace std;
#define upper_bound 1 // total number of folders starting from 0
std::string to_string(int i) {
std::stringstream s;
s << i;
return s.str();
}
int main()
{
for( int i=0;i<=upper_bound;i++)
{
string s = ".\\input";
string s1=".\\";
string p= ".txt";
string Input = s;
string CopiedFile = to_string(i)+p;
string OutputFolder = s1+to_string(i);
CopyFile(Input.c_str(), string(OutputFolder+CopiedFile).c_str(), TRUE);
}
}
But when I run it, nothing is copied. is there anything wrong in this? How will I copy those files?

You're trying to copy the file ".\input.txt" to ".\1\1.txt
input.txt might not exist in the current directory; try setting this to an absolute path
You never create the directory "1" (again in the random working directory). The documentation doesn't say that it will create the directory for you if it doesn't exist; so you should probably make sure that it does & create it if it doesn't.

This is the syntax of the function:
BOOL WINAPI CopyFile(
_In_ LPCTSTR lpExistingFileName, // absolute input path.
_In_ LPCTSTR lpNewFileName, // absolute output path
_In_ BOOL bFailIfExists // to determine if you want to prevent the
//file from being replaced
);
Your input path must be absolute. Your file's input path isn't absolute. It just addresses the file's directory and not the exact file.
Replace the below
string Input = s;
with:
string Input = s + String("\\") + to_string(i) + p;
I have 2 files named 0.txt and 1.txt in a input folder
So you must address both these files directly. But for each iteration the variable input only holds the string ".\\input" which is the directory and not the absolute path.

Related

How to run a c++ program multiple times with different input files?

I'm new to C++ and writing my master thesis and would really appreciate any help I can get!
I have a program that reads a txt file, then does a bunch of calculations, and returns a new txt file. The thing is that I want to run this program for 100+ different input files. Now I have to change the name of the input file in the code, but I would like to have it run for all the input files in my folder by itself.
I am using Visual Studio, but with little C++ experience.
Thanks :)
See this snippet. Since you are using MSCV, you need to enable MFC in configuration for this console application. Also add #include "afx.h" in #include "stdafx.h" where CFileFind is defined. PopulateFromFolder() should auto load the files into the vector files.
#include "stdafx.h"
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
void PopulateFromFolder(string path, vector<string>& files)
{
CFileFind finder;
CString fileName;
fileName.Format(L"%s*.*", CString(path.c_str()));
BOOL bOk = finder.FindFile(fileName);
while (bOk)
{
bOk = finder.FindNextFile();
if (finder.IsDots())
{
continue;
}
if (!finder.IsDirectory())
{
CString strFileName = finder.GetFileName();
files.push_back(CStringA(strFileName).GetString());
}
}
finder.Close();
}
int main()
{
vector<string> files;
string path = "D:\\MyFolder\\";
PopulateFromFolder(path, files);
auto a = path + files[0];
int i = 0;
while (i< files.size()-1)
{
cout << "processing " << files[i + 1] << endl;
ifstream fs(path+files[i++]);
if (fs.is_open())
{
//do something
}
fs.close();
}
return 0;
}
Output:
Using bash you can run them using:
$ for file in /Data/*.txt; do /path/your_program $file; done
You can define format for your input files names and put then into some directory. For example,
Input1.txt
Input2.txt
...
Input111.txt
Then use some kind of for loop:
for(int i = 1; i <= 111; ++i)
{
ifstream file("Input" + std::to_string(i) + ".txt");
if (file.is_open())
Operate(file);
}
If you don't know the exact number of files, you can check whether the file was openen by is_open() method. This way files with some numbers can be absent. You just loop for some max possible input file id.
This was a solution which doesn't require any dependencies. But if you don't mind it, you actually may consider Boost.Filesystem. Here is an example.
You can try to use std::experimental::filesystem (http://en.cppreference.com/w/cpp/experimental/fs). I guess that directory_iterator from this library can be useful for you - it allows you to iterate over all files in a given directory. Have a look at the example provided in the documentation: http://en.cppreference.com/w/cpp/experimental/fs/directory_iterator.
However, you have to make sure that you are compiling your code with a new standard (C++ 17).
Another way is to make for example a separate file containing a list of the names of all files that you want to work on. Then, you can read this list and for every file do what you need.

c++ ofstream write_to_log.open (" relative path + array");

I want the line below to write a new file using the content given in the array
but into a new folder named logs:
char log_file_name[100]; /* this array contains the name of a new file */
ofstream write_to_log;
write_to_log.open (relative path, log_file_name , fstream::app);
How do I get it working ?
You can use CreateDirectory for creating folders with VC++ in Windows.
#include <windows.h>
#include <string>
#include <fstream>
using namespace std;
int main() {
string path = "C:\\users\\folder";
CreateDirectory(path.c_str(), NULL);
char log_file_name[100] = "log.txt";
path += '\\';
path += log_file_name;
ofstream write_to_log(path.c_str(), fstream::app);
return 0;
}
The NULL refers to a security attributes structure that you may have to create. More details at MSDN here and in this answer.
You can save your self a lot of potential trouble and replace char log_file_name[100]; with std::string log_file_name; The benefits of string are many, the most important here are they resize and they make appending really easy. The string does everything a char array does and a whole lot of extras. In virtually all cases, you should chose a string over a char array.
string path;
string log_file_name;
With the path and the file name as strings
path += "\\" + log_file_name
ofstream write_to_log(path, fstream::app);
if (write_to_log)
{ // file is open and looks writable (have to start writing to be sure)
// do stuff. Or not. It's a free country.
}
else
{ // file didn't open
// Handle error
}
All done and the file, if it exists and is writable, is open and ready to go. Always check the state of a stream when you use it. SO is littered with questions from people who didn't and got confused by the result.
On older compilers you may have to change the create and open line slightly:
ofstream write_to_log(path.c_str(), fstream::app);

scan directory to find and open the file

I want to make a program that lets user enter drive name/folder(C:\ or f:\folder\) and a file name (test.exe) then program searches that file in the given drive or folder and opens the file.I managed to do the function that opens the file but cannot figure out how to search the file pass the location of file found to open it. Can anyone help me?
You can use boost::file_system. Here is documentation: http://www.boost.org/doc/libs/1_55_0/libs/filesystem/doc/index.htm
EDIT: after some time, I've got that my ansver were sligtly out of topic. To check if file exists you can use special boost::filesystem function.
bool exists(const path& p);
/EDIT
And directory iterator example: http://www.boost.org/doc/libs/1_55_0/libs/filesystem/doc/tutorial.html#Directory-iteration
It that example used std::copy, but you need filenames. So you can do something like this.
#include <boost/filesystem.hpp>
namespace bfs = boost::filesystem;
std::string dirPath = "."; // target directory path
boost::filesystem::directory_iterator itt(bfs::path(dirPath)); // iterator for dir entries
for ( ; itt != boost::filesystem::directory_iterator(); itt++)
{
const boost::filesystem::path & curP = itt->path();
if (boost::filesystem::is_regular_file(curP)) // check for not-a-directory-or-something-but-file
{
std::string filename = curP.string(); // here it is - filename in a directory
// do some stuff
}
}
If you are not expirienced with boost - building it can be complicated.
You can obtain prebuilded boost binaries for your compiller and platform at boost.teeks99.com
Also, if you cant use boost for some reason, there is platform specific ways of iterating a directory, but I dont know on which platform you are, so I cant provide you an example.
Try this:
char com[50]="ls ";
char path[50]="F:\\folder\\";
char file[50]="test.exe";
strcat(com,path);
strcat(com,file);
if (!system(com)) // system returns the return value of the command executed
cout<<"file not present\n";
else
{
cout<<"file is present\n";
strcat(path,file);
FILE* f = fopen(path,"r");
//do your file operations here
}

Writing image file names within folders into a text file c++

I wrote a little bit of code to easily add the file names of images i had within a directory and add them to a list in a text file. This worked fine, but when the images were within a sub-folder it would just add the folder name as an entry into the text file.
I need it to be able to check whether it's a folder and then add the correct directory into the text for the images which might be within the sub-folder, e.g subfolder/image.jpg
Can't work out what i'd need to add. This is what I've got so far...
#include<stdio.h>
#include<cstdlib>
#include<iostream>
#include<string.h>
#include<fstream>
#include<dirent.h>
void listFile();
std::ofstream myfile;
int main(){
listFile();
return 0;
}
void listFile(){
DIR *pDIR;
struct dirent *entry;
if( pDIR=opendir("/home/hduser/Example2Files/TrainImages/") ){
while(entry = readdir(pDIR)){
if( strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0 )
myfile.open ("/home/hduser/Example2Files/TrainImages/train.txt",std::ios_base::app);
myfile << entry->d_name << "\n";
myfile.close();
}
closedir(pDIR);
}
}
To traverse into directories, you will (probably) have to modify your code such that you have a function that takes the name of a directory, and lists regular files within that directory. If it finds a directory, it should call recursively with the concatenated name of the current directory and the found directory.
To identify if the file is a directory, you can use something like entry.d_type == DT_DIR.

New to <dirent.h>, trying to access data in a directory

I've never used dirent.h before. I was using istringstream to read through text files (singular), but have needed to try to revise the program to read in multiple text files in a directory. This is where I tried implementing dirent, but it's not working.
Maybe I can't use it with the stringstream? Please advise.
I've taken out the fluffy stuff that I'm doing with the words for readability. This was working perfectly for one file, until I added the dirent.h stuff.
#include <cstdlib>
#include <iostream>
#include <string>
#include <sstream> // for istringstream
#include <fstream>
#include <stdio.h>
#include <dirent.h>
void main(){
string fileName;
istringstream strLine;
const string Punctuation = "-,.;:?\"'!##$%^&*[]{}|";
const char *commonWords[] = {"AND","IS","OR","ARE","THE","A","AN",""};
string line, word;
int currentLine = 0;
int hashValue = 0;
//// these variables were added to new code //////
struct dirent *pent = NULL;
DIR *pdir = NULL; // pointer to the directory
pdir = opendir("documents");
//////////////////////////////////////////////////
while(pent = readdir(pdir)){
// read in values line by line, then word by word
while(getline(cin,line)){
++currentLine;
strLine.clear();
strLine.str(line);
while(strLine >> word){
// insert the words into a table
}
} // end getline
//print the words in the table
closedir(pdir);
}
You should be using int main() and not void main().
You should be error checking the call to opendir().
You will need to open a file instead of using cin to read the contents of the file. And, of course, you will need to ensure that it is closed appropriately (which might be by doing nothing and letting a destructor do its stuff).
Note that the file name will be a combination of the directory name ("documents") and the file name returned by readdir().
Note too that you should probably check for directories (or, at least, for "." and "..", the current and parent directories).
The book "Ruminations on C++" by Andrew Koenig and Barbara Moo has a chapter that discusses how to wrap the opendir() family of functions in C++ to make them behave better for a C++ program.
Heather asks:
What do I put in getline() instead of cin?
The code at the moment reads from standard input, aka cin at the moment. That means that if you launch your program with ./a.out < program.cpp, it will read your program.cpp file, regardless of what it finds in the directory. So, you need to create a new input file stream based on the file you've found with readdir():
while (pent = readdir(pdir))
{
...create name from "documents" and pent->d_name
...check that name is not a directory
...open the file for reading (only) and check that it succeeded
...use a variable such as fin for the file stream
// read in values line by line, then word by word
while (getline(fin, line))
{
...processing of lines as before...
}
}
You probably can get away with just opening the directories since the first read operation (via getline()) will fail (but you should probably arrange to skip the . and .. directory entries based on their name). If fin is a local variable in the loop, then when the outer loop cycles around, fin will be destroyed, which should close the file.