user1908860
user1908860

Reputation: 519

A file operation in C++ for both iOS and Android

I need to perform a certain file operation in C++, like this:

  1. Find and delete all files in a given directory.
  2. Find if a given file exist, if yes, delete it, etc.

Please advise me a C++ solution/library which will work for both android and iOS platform.

Upvotes: 2

Views: 4558

Answers (4)

Shark
Shark

Reputation: 6610

IF you are working for Android, you are probably gonna be writing some of your game in the Java Activity and then delegate most of the heavy work to your native C/C++ code.

So, if Steven Lu's answer isn't working out of the box, you can use Java's File class and list all filenames under any directory, and then pass that to his native file handling class and get it over with. Or, just deal with it in Java.

For iOS though, maybe this will run?

#include <dirent.h> // directory header
#include <stdio.h>

void listdir (const char *path)
{
    // first off, we need to create a pointer to a directory
    DIR *pdir = NULL; 
    pdir = opendir (path); // "." will refer to the current directory
    struct dirent *pent = NULL;
    if (pdir == NULL) // if pdir wasn't initialised correctly
    { // print an error message and exit the program
        printf ("\nERROR! pdir could not be initialised correctly");
        return; // exit the function
    } // end if

    while (pent = readdir (pdir)) // while there is still something in the directory to list
    {
        if (pent == NULL) // if pent has not been initialised correctly
        { // print an error message, and exit the program
            printf ("\nERROR! pent could not be initialised correctly");
            return; // exit the function
        }
        // otherwise, it was initialised correctly. let's print it on the console:
        printf ("%s\n", pent->d_name);
    }

    // finally, let's close the directory
    closedir (pdir);
}


/** EXAMPLE USAGE **/
int main ()
{
    listdir ("C:\\");
    return 0;
}

But like I said, Android will give you bigger problems as you will need to request permissions to access the SD_CARD and INTERNAL_STORAGE if you want to mess with user's files in the AndroidManifest.xml file. Mostly because most of your stuff will be just in /data/data/your.package.name folder because you will have to ship your game as an APK and not a native app (an executable binary)

So, you don't really need an android and ios library, you need a library that can run on iOS which you will later wrap around with Android's Java (Activity) :)

Upvotes: 0

Steven Lu
Steven Lu

Reputation: 43427

C++ gives you provisions for file interaction.

I will show you my FileReader class which employs a bit of C style file handling using C++.

// BEGIN HEADER
#include <stdio.h>
#include <exception>
#include <stdexcept>

#define DISALLOW_COPY(type) \
    type(const type&); \
    void operator=(const type&)

class FileReader { // RAII applies to file contents
    FILE *file; // c-style open/close
    DISALLOW_COPY(FileReader);
protected:
    unsigned char *data; // local copy
    long size;
public:
    FileReader(const char *filename);
    ~FileReader();
    unsigned long getSize();
    unsigned char *getFileData();
};
// END HEADER

FileReader::FileReader(const char *filename) {

    file = NULL; data = NULL;
    if (!(file = fopen(filename, "rb"))) { throw std::runtime_error(std::string("File could not be opened: ")+filename); }
    fseek(file,0,SEEK_END);
    size = ftell(file);
    rewind(file);
    data = new unsigned char [size];
    VERIFY(size == (long)fread(data, 1, size, file)); // debug macro (just ignore it)
    fclose(file);
#ifdef DEBUG
    PRINT("FileReader opening file "); printf("%s, %ld bytes.\n",filename,size);
#endif
}
FileReader::~FileReader() {
    delete[] data;
}
unsigned char *FileReader::getFileData() { return data; }
unsigned long FileReader::getSize() { return size; }

I will note that you probably want to avoid using C++ to list files in the directory if you can. Why can you not simply assume whether or not certain files will be there or not be there? I've done a bit of game programming and pretty much the only times you need to worry about the filesystem are for logging purposes or for loading assets. For both of these you can pretty much just assume what their paths are.

In addition, you may want to look at the remove function for deleting files. I can't come up with any raw code in C++ for performing the task that ls is meant for. I wouldn't use C++ to do such a task (hint: ls is a pretty neat program).

Also take a look at stat and opendir (thanks Ben) which should be available on your platforms. Another point to make is that a task such as listing files in a dir are generally things you're gonna want to ask your OS kernel to do for you.

A more high-level approach mentioned by another answerer is Boost Filesystem, which is a solid choice as Boost usually is: Take a look at this directory iteration example.

From a game programming perspective I've tended to lean on stuff like Lua's os(). For example if you have a Python program you could just do something like os.system("ls") to get your dir contents assuming you have an ls program available.

You could also exec the ls program from your C++ program.

Upvotes: 1

amrav
amrav

Reputation: 307

You could try using the Boost library, which seems to be a popular choice. It runs on iOS and Android.

See this answer on SO for more info on how to use Boost to manipulate files and directories in a cross platform way.

For example, here's some code from the Boost website to check if a particular file exists or not, checking recursively in a directory:

#include "boost/filesystem/operations.hpp"
#include "boost/filesystem/path.hpp"
#include "boost/progress.hpp"
#include <iostream>

namespace fs = boost::filesystem;

int main( int argc, char* argv[] )
{
  boost::progress_timer t( std::clog );

  fs::path full_path( fs::initial_path<fs::path>() );

  if ( argc > 1 )
    full_path = fs::system_complete( fs::path( argv[1] ) );
  else
    std::cout << "\nusage:   simple_ls [path]" << std::endl;

  unsigned long file_count = 0;
  unsigned long dir_count = 0;
  unsigned long other_count = 0;
  unsigned long err_count = 0;

  if ( !fs::exists( full_path ) )
  {
    std::cout << "\nNot found: " << full_path.file_string() << std::endl;
    return 1;
  }

  if ( fs::is_directory( full_path ) )
  {
    std::cout << "\nIn directory: "
              << full_path.directory_string() << "\n\n";
    fs::directory_iterator end_iter;
    for ( fs::directory_iterator dir_itr( full_path );
          dir_itr != end_iter;
          ++dir_itr )
    {
      try
      {
        if ( fs::is_directory( dir_itr->status() ) )
        {
          ++dir_count;
          std::cout << dir_itr->path().filename() << " [directory]\n";
        }
        else if ( fs::is_regular_file( dir_itr->status() ) )
        {
          ++file_count;
          std::cout << dir_itr->path().filename() << "\n";
        }
        else
        {
          ++other_count;
          std::cout << dir_itr->path().filename() << " [other]\n";
        }

      }
      catch ( const std::exception & ex )
      {
        ++err_count;
                                                                                                                                                                        std::cout << dir_itr->path().filename() << " " << ex.what() << std::endl;
      }
    }
    std::cout << "\n" << file_count << " files\n"
              << dir_count << " directories\n"
              << other_count << " others\n"
              << err_count << " errors\n";
  }
  else // must be a file
  {
    std::cout << "\nFound: " << full_path.file_string() << "\n";    
  }
  return 0;
 }

Upvotes: 1

Naszta
Naszta

Reputation: 7744

Boost filesystem is fine for you. iOS version and clang++. Boost and NDK.

Upvotes: 1

Related Questions