Writing image file names within folders into a text file c++ - 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.

Related

copy multiple text files from a folder into different folders in 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.

ifstream not working with dirent.h

I'm testing optimizations for dijkstra algorithm and to make it easier to open files I used "dirent.h" to get all the test files in the running path and then ifstream to open this file.
the readDirec method reads all the files in the directory and ignores folder and puts those files names in a vector called files.
void selectDirec(){
files.clear();
DIR *dir;
struct dirent *ent;
if ((dir = opendir (".")) != NULL) {
while ((ent = readdir (dir)) != NULL) {
if(opendir(ent->d_name) == NULL){
files.push_back(ent->d_name);
}
}
closedir (dir);
} else {
cout<<"directory error"<<endl;
}
}
after that I uses a function called selectFile which assigns the name of the file the user chooses to a variable called fileName.
void selectFile(){
selectDirec();
for(int i = 0 ; i < files.size() ; i++){
cout<<i+1<<" : "<<files[i]<<endl;
}
int choice = 0;
do{
cout<<"enter file number"<<endl;
cin>>choice;
}while(choice > files.size());
choice--;
fileName = files[choice];
cout<<fileName<<":"<<endl;
}
after that I enter my readGraph function which opens the file and continue graph operations
void readGraph(){
ifstream ifile; ifile.open(fileName);
if(!ifile.is_open()){
cout<<"no file with the name specified"<<endl;
eflag = true;
return;
}
...
...
}
initialization:
vector<char *> files;
char * fileName ;
now I have those 5 files to test which I got from here http://algs4.cs.princeton.edu/44sp/:
tinyEWD.txt contains 8 vertices and 15 edges [140B]
mediumEWD.txt contains 250 vertices and 2,546 edges[40KB]
1000EWG.txt contains 1,000 vertices and 16,866 edges[313KB]
10000EWG.txt contains 10,000 vertices and 123,462 edges[2.4MB]
NYC.txt . contains 264346 vertices and 733846 edges[12.7MB].
but there's a weird problem with those 3 files:
'mediumEWD' , '10000EWD.txt' , 'NYC.txt'
when I choose any of them the code shows me "no file with the name specified" that in the else statement in readGraph.
but when I enter their name manually and comment selectDirec and selectFile the program opens them successfully.
P.S. I checked the file name and spacing and everything.
P.S.2 currently running this code on ubuntu 14.04 LTS.
thanks in advance.
if(opendir(ent->d_name) == NULL){
files.push_back(ent->d_name);
}
What is files? I suspect that you are using a std::vector<const char *>, or something along the same lines.
This won't work. d_name is a part of the dirent structure. Immediately afterwards, and certainly after the closedir(), that pointer is no longer valid, and points to deallocated memory.
Looks to me like you then proceed and attempt to use the no-longer valid pointer as the filename parameter to std::ifstream.
You should use a std::vector<std::string> to store the filenames, and use the c_str() member function to extract a pointer to a C-style string, for the open() call.
You can't be using a vector of std::strings here, this must be a vector of raw character pointers. That's because you're assigning one of its values to fileName, whatever it is, and then passing it directly to open() without using c_str(). So it can't be a vector of strings.

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
}

C++ code not finding file

I'm trying to create a program that will concatenate (add two lists of integers together)
each list is stored as a text file. I want the C++ program to open list1.txt and list2.txt
I can't actually get it to work though. I've put two lists of integers names list1 and list2 respectively however I'm getting the output cannot find list1.
#include <iostream>
#include <fstream>
#include <ostream>
using namespace std;
int main()
{
ifstream findlist1("list1.txt", ios::in | ios::binary);
if(!findlist1)
{
cout << "Cannot find list 1.\n";
return 1;
}
ifstream findlist2("list2.txt", ios::in | ios::binary);
if(!findlist2)
{
cout << "Cannot find list 2.\n";
return 1;
}
ofstream out("list3out.txt", ios::out | ios::binary);
if(!out)
{
cout << "Unable to output file ";
return 1;
}
out << in1.rdbuf();
out << " " << flush;
out << in2.rdbuf();
return 0;
}
EDIT = SOLUTION:
My files were called test1.txt and were therefore showing up to the program as test1.txt.txt
The code looks fine, you may try using absolute path or put the files in the same directory of executable
If you are using Visual Studio, all relative paths are relative to the project's working directory. The default seems to be the project directory - meaning that if in C:\SolutionX\ProjectY\Build\ProjectY.exe you try to open the path "file.txt", Windows will look for C:\SolutionX\ProjectY\file.txt. If you'd like to change this directory, the setting is in the project's Configuration Properties under Debugging as "Working Directory".
Note that if you double click the executable manually rather than running it through Visual Studio, its working directory will be its current location. If instead you run the program from a command line, the working directory will be your working directory in the command line.

directory_iterator file_iter to rename files in a folder

I wanted to rename the files in a directory.There are 52 folders in the directory. Each folder has a different name and has around 40 files in each of them.I wanted to extract the name of a particular folder and attach that name to the name of the files in that particular folder.
It worked fine, when there was only 31 or less files in each folder. But whenever the number of files in a particular folder was above 31 the rename algorithm i wrote failed. I am not able to figure out why it crashes when there are more files. Do enlighten me if u understand why...!
I'm attaching the code:
int main( int argc, char** argv ){
directory_iterator end_iter;
directory_iterator file_itr;
string inputName;
string checkName;
inputName.assign(argv[1]);
if (is_directory(inputName))
{
for (directory_iterator dir_itr(inputName); dir_itr != end_iter; ++dir_itr)
{
if (is_directory(*dir_itr))
{
for (directory_iterator file_itr(*dir_itr); file_itr != end_iter; ++file_itr)
{
string folderName(dir_itr->path().filename().string());
if (is_regular_file(*file_itr))
{
std::string fileType = file_itr->path().extension().string();
std::transform(fileType.begin(), fileType.end(), fileType.begin(), (int(*)(int))std::toupper);
if (fileType == ".JPG" || fileType == ".JPEG" || fileType == ".JPG" || fileType == ".PGM")
{
string filename(file_itr->path().string());
string pathName(file_itr->path().parent_path().string());
string oldName(file_itr->path().filename().string());
cout << folderName << endl;
folderName += "_";
folderName += oldName;
string newPathName = pathName + "\\" + folderName;
cout << pathName <<"\\"<< folderName << endl;
//RENAMING function
rename(file_itr->path(), path(newPathName.c_str()));
}
}
}
}
}
}
}
It's likely that Boost's directory_iterator implementation is getting confused by you renaming files that are in the directory listing.
From the docs:
Warning: If a file or sub-directory is removed from or added to a directory after the construction of a directory_iterator for the directory, it is unspecified whether or not subsequent incrementing of the iterator will ever result in an iterator whose value is the removed or added directory entry.
I recommend trying it in two phases. In the first phase, use the code you have now to build a vector<pair<string, string> > instead of renaming the file. Then, once you've scanned the directory, it should just be a matter of iterating through the list performing the actual renames.