How should I go about searching the entire files/folders from a given PATH, and searching all of it's contents for a specific string for example?
I know I'd have to do it recursively somehow, unless there's a function to search for everything in a path. And that I'd have to open each file found and check for that specific string in it. But how does Visual Studio open files? Can it open any kind of files, or just text-based ones?
All I've managed to get so far is:
#include <iostream>
#include <filesystem>
using namespace std;
namespace fs = std::experimental::filesystem;
void ShowFiles(string path)
{
for (auto &p : fs::directory_iterator(path))
cout << p.path().filename() << '\n';
}
int main()
{
ShowFiles("D:/TEST/testFOLDER/");
}
Which only prints the folders/files in the given PATH, but not the ones inside folders of it.
EDIT: should i use DIR* and dirent* ? would it be any easier?
Use recursive_directory_iterator instead.
For reading the file, use std::ifstream. It has been updated to take a path object in C++17.
Related
I'm trying to write a program that moves files from one directory to another, so far I have this written.
void file_Move(ifstream in,ofstream out)
{
string name, name2;
int downloads;
cout << "Enter 1 if the file you wish to move is in downloads" << endl;
cin >> downloads;
if (downloads == 1)
{
opendir("F:/Downloads"); //supposed to open the directory so that the user can input the file they wish to be moved.
closedir("F:/Downloads");
}
}
Visual Studio doesn't have the dirent.h library which is necessary for opendir and closedir, so I was wondering if there was a similar or better way of doing what those do.
Your code doesn't make much sense as it stands right now.
On one hand, file_move takes an ifstream and an ofstream, which would imply that you've already found and opened the files you care about. Then it goes on to attempt to search for files...
For the moment, I'm going to assume you need to search for the files you care about. In this case, you probably want to use the filesystem library. With a really up to date compiler, this may be directly in std::. For a slightly older compiler, it may be in std::experimental. For one that's older still (predates the Filesystem TS) you'll probably need to use Boost Filesystem instead.
In any case, code to use this would run something like this:
#include <string>
#include <filesystem>
#include <iostream>
#include <iterator>
#include <algorithm>
void show_files(std::string const & path) {
// change to the std or Boost variant as needed.
namespace fs = std::experimental::filesystem::v1;
fs::path p{ path };
fs::directory_iterator b{ p }, e;
std::transform(b, e,
std::ostream_iterator<std::string>(std::cout, "\n"),
[](fs::path const &p) {
return p.string();
}
);
}
Of course, if you're going to copy files, you probably want to put the file names in a vector (or something on that order) rather than just displaying them--but presumably you know how to do what you want once you have file names to work with.
In any case, to call this you can just pass the path to the directory you care about, such as F:/Downloads:
show_files("f:/Downloads");
Of course, under a system that uses POSIX paths, you'll pass a different input string (e.g., might be something like "/home/some_user/Downloads" instead). Oh, and at least with its usual directory structure, with g++ the header will be experimental/filesystem instead of just filesystem.
I want to make a program that can search through a specific folder on my computer to find certain files. In this case I want it to look for text files. I've heard some sources claim that this can be done using the standard C++ library. If so, how can I go about doing this? I believe the working code should look something like this:
string path = "C:\\MyFolder\\";
while(/*Searching through the directory*/)
{
if (/*File name ends with .txt*/)
{
/*Do something*/
}
}
There's no support for working with directories in the standard library. There's however an effort to incorporate Boost.Filesystem into the C++17 standard. For now, you can just use Boost directly.
#include <iostream>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string/predicate.hpp>
int main(int argc, char* argv[])
{
namespace fs = boost::filesystem;
namespace ba = boost::algorithm;
fs::path dir_path(".");
for (const auto& entry : fs::directory_iterator(dir_path)) {
if (fs::is_regular_file(entry)) {
std::string path = entry.path().string();
if (ba::ends_with(path, ".txt")) {
// Do something with entry or just print the path
std::cout << path << std::endl;
}
}
}
}
update:
To compile the snippet, you need to have Boost installed (and compiled, Filesystem is not header-only). Follow the tutorials here. Then make sure to link with boost_filesystem:
g++ -std=c++11 -Wall test.cc -lboost_filesystem && ./a.out
And don't forget to create some .txt files in the same directory so that the program has something to chew on.
I'm new to C++ and I've just read <C++ Primer> 4ed. Now I want to implement a little program to help me manage some mp3 files in my computer.
I have a .txt file which includes all the names(part of the names actually) of the files which I want to move(not copy) to a new folder(in the same column). For example, "word" and "file" in the .txt and I want to move all the .mp3 files whose filename contain "word" or "file" to a new folder. Hope my discription is clear, Opps..
I know how to read the strings in .txt into a set<string> and traverse it, but I have no idea how to search and move a file in a folder. I just want to know what else should I learn so that I can implement this function. I read C++ Primer and still I can't do much thing, that's really sad...
To move a file in C++, you do not have to use external libraries like Boost.Filesystem, but you can use standard functionality.
There is the new filesystem API, which has a rename function:
#include <iostream>
#include <filesystem>
int main() {
try {
std::filesystem::rename("from.txt", "to.txt");
} catch (std::filesystem::filesystem_error& e) {
std::cout << e.what() << '\n';
}
return 0;
}
The drawback is to compile it, you need a recent C++17 compiler. (I tested it on gcc 8.0.1, and I also needed to link against -lstdc++fs).
But what should work on any C++ compiler today, is the old C API, which also provides rename (cstdio):
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cerrno>
int main() {
if(std::rename("from.txt", "to.txt") < 0) {
std::cout << strerror(errno) << '\n';
}
return 0;
}
But note that in both cases, the rename will fail if the source and destination files are not on the same filesystem. Then you will see an error like this:
filesystem error: cannot rename: Invalid cross-device link [from.txt] [/tmp/to.txt]
In that case, you can only make a copy and then remove the original file:
#include <fstream>
#include <iostream>
#include <ios>
#include <cstdio>
int main() {
std::ifstream in("from.txt", std::ios::in | std::ios::binary);
std::ofstream out("to.txt", std::ios::out | std::ios::binary);
out << in.rdbuf();
std::remove("from.txt");
}
Or with the new API:
#include <iostream>
#include <filesystem>
int main()
{
try {
std::filesystem::copy("from.txt", "to.txt");
std::filesystem::remove("from.txt");
} catch (std::filesystem::filesystem_error& e) {
std::cout << e.what() << '\n';
}
return 0;
}
Use rename() function to move a file
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
char oldname[] = "C:\\Users\\file_old.txt";
char newname[] = "C:\\Users\\New Folder\\file_new.txt";
/* Deletes the file if exists */
if (rename(oldname, newname) != 0)
perror("Error moving file");
else
cout << "File moved successfully";
return 0;
}
The only way for this to work only using std would be to read the file completely using a std::ifstream and then write it to the new location with a std::ofstream. This will however not remove the old file from disk. So basically you create a copy of the file. Its also much slower than a real move.
The optimal solution is to use OS specific APIs like win32 which e.g provide a MoveFile() function. Poco provides an platform independent abstraction of such APIs. See: http://www.appinf.com/docs/poco/Poco.File.html
Another way to move a file in Windows is using the MoveFile function as it is shown in the following code.
std::wstring oldPath = L"C:\\Users\\user1\\Desktop\\example\\text.txt";
std::wstring newPath = L"C:\\Users\\user1\\Desktop\\example1\\text.txt";
bool result = MoveFile(newPath.c_str(), oldPath.c_str());
if (result)
printf("File was moved!");
else
printf("File wasn't moved!");
under Windows run system call with batch commands:
system("move *text*.mp3 new_folder/");
system("move *word*.mp3 new_folder/");
Under Unix same with shell syntax.
I'm planning to make a program that would work between a folder on my computer and my NAS.
It would list all the files in both folders, then determine which file is newer, and then upload it to the other device.
I know how to upload files via FTP, but I'm stuck at the start, because I don't know how to list my files. I have looked a little at using FindFirstFile() and FindNextFile() with WIN32_FIND_DATA. This way, I can get the last write data, but this doesn't let me list subdirectories.
Do you know any easy way listing all files in a folder and its subdirectory and saving the information of every file in a list?
The easy way is to use boost::recursive_directory_iterator.
#include <boost/foreach.hpp>
#include <iostream>
#include <vector>
#include <boost/filesystem.hpp>
#include <boost/date_time.hpp>
#include <algorithm>
#include <iterator>
#include <ctime>
using boost::filesystem::path;
using boost::filesystem::recursive_directory_iterator;
using boost::filesystem::directory_entry;
using boost::filesystem::filesystem_error;
using boost::filesystem::last_write_time;
using std::vector;
using std::cout;
using std::copy;
using std::ostream_iterator;
using std::time_t;
using boost::posix_time::from_time_t;
int main(int ac, const char **av)
{
vector<const char*> args(av+1, av+ac);
if(args.empty())
args.push_back(".");
vector<directory_entry> files;
BOOST_FOREACH(path p, args)
{
boost::system::error_code ec;
copy(recursive_directory_iterator(p, ec),
recursive_directory_iterator(),
back_inserter(files));
}
BOOST_FOREACH(const directory_entry& d, files)
{
if(exists(d.path()))
{
cout << from_time_t(last_write_time(d.path())) << " " << d.path() << "\n";
}
}
}
FindFirstFile() and FindNextFile() does let you list subdirectories. One of the members of WIN32_FIND_DATA is dwFileAttributes which will include FILE_ATTRIBUTE_DIRECTORY for a directory entry. Simply start another FindFirstFile() in that subdirector, rinse, repeat.
There is a sample on MSDN that shows how to use the FindFirstFile API, here.
I need to be able to open a file when i only know part of the file name. i know the extension but the filename is different every time it is created, but the first part is the same every time.
You'll (probably) need to write some code to search for files that fit the known pattern. If you want to do that on Windows, you'd use FindFirstFile, FindNextFile, and FindClose. On a Unix-like system, opendir, readdir, and closedir.
Alternatively, you might want to consider using Boost FileSystem to do the job a bit more portably.
On a Unix-like system you could use glob().
#include <glob.h>
#include <iostream>
#define PREFIX "foo"
#define EXTENSION "txt"
int main() {
glob_t globbuf;
glob(PREFIX "*." EXTENSION, 0, NULL, &globbuf);
for (std::size_t i = 0; i < globbuf.gl_pathc; ++i) {
std::cout << "found: " << globbuf.gl_pathv[i] << '\n';
// ...
}
return 0;
}
Use Boost.Filesystem to get all files in the directory and then apply a regex (tr1 or Boost.Regex) to match your file name.
Some code for Windows using Boost.Filesystem V2 with a recursive iterator :
#include <string>
#include <regex>
#include <boost/filesystem.hpp>
...
...
std::wstring parent_directory(L"C:\\test");
std::tr1::wregex rx(L".*");
boost::filesystem::wpath parent_path(parent_directory);
if (!boost::filesystem::exists(parent_path))
return false;
boost::filesystem::wrecursive_directory_iterator end_itr;
for (boost::filesystem::wrecursive_directory_iterator itr(parent_path);
itr != end_itr;
++itr)
{
if(is_regular_file(itr->status()))
{
if(std::tr1::regex_match(itr->path().file_string(),rx))
// Bingo, regex matched. Do something...
}
}
Directory iteration with Boost.Filesystem. // Getting started with regular expressions using C++ TR1 extensions // Boost.Regex
I think you must get list of files in a directory - this [link] will help you with it.
After that, I think will be quite easy to get a specific file name.