Search code examples
androidandroid-filexbmc

Android File Copying: Path Error


I have been trying to copy a file from one location to another. To my understanding the copying mechanism of my program is working properly, however when I run the app I constantly get a file path error. I happen to be working with the data files within the xbmc app.

AssetManager-->addDefaultAssets CIP path not exsit /data/data/org.xbmc.xbmc/.xbmc/userdata/guisettings.bak: open failed: ENOENT (No such file or directory)

The problem seems to occur when I create File objects for the string paths. Here is the code snippet for that portion of the program:

File inputFile = new File(inputPath);
File outputFile = new File(outputPath);

No matter how I try to access the files, I keep getting the above error. I have tried using the File, FileInputStream, and Uri libraries to get the file paths with no luck. Could I be having issues with write privileges, or am I just not specifying the file paths correctly? I am posting the whole solution just in case the problem lies elsewhere within the code.

public class myActivity extends Activity {
    private static final String TAG = "myActivity.java";
    //The package name representing the application directory that is to be accessed
    String packageName = "org.xbmc.xbmc";
    //The input filename to read and copy
    String inputFileName = "guisettings.bak";
    //The output filename to append to
    String outputFileName = "guisettings.xml";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        //Check the status of the external storage
        if(isExternalReady()) {
            //The external file system is ready
            //Start the specific file operation
            restoreFile();
        } else {
            //Not ready. Create a Broadcast Receiver and wait for the filesystem to mount
            BroadcastReceiver mExternalInfoReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context arg0, Intent intent) {
                    //The external filesystem is now mounted
                    //Start the specific file operation
                    restoreFile();
                }
            };
            //Get the IntentFilter Media Mounted
            IntentFilter filter = new IntentFilter(Intent.ACTION_MEDIA_MOUNTED);
            //Specify the filesystem data type
            filter.addDataScheme("file");
            //Register the receiver as "mExternalInfoReceiver" with the Media Mount filter
            registerReceiver(mExternalInfoReceiver, new IntentFilter(filter));
        }
    }

    //Restore the specific xml file
    public void restoreFile() {
        /*
        //Get the internal storage of this app (Android/data/com.website.appname/files/)
        String internalStorage = Environment.getFilesDir();
        //Get the external storage path now that it is available
        String externalStorage = Environment.getExternalStorageDirectory().toString();
        //The directory of the file desired
        String filePath = "Android/data/org.xbmc.xbmc/files/.xbmc/userdata/";
        */
        //The information of the desired package
        ApplicationInfo desiredPackage;
        //Get the path of the application data folder if the application exists
        try {
            //Get the info of the desired application package
            desiredPackage = getPackageInfo(packageName);
        } catch (Exception e) {
            //Output the stack trace
            e.printStackTrace();
            //Stop the function
            return;
        }
        //Get the data dir of the package
        String rootPackageDir = desiredPackage.dataDir;
        //The path to the file in the package
        String packageFilePath = "/.xbmc/userdata/";
        //Construct the complete path of the input and output files respectively
        //based on the application path
        String inputPath = String.format("%s%s%s", rootPackageDir, packageFilePath, inputFileName);
        String outputPath = String.format("%s%s%s", rootPackageDir, packageFilePath, outputFileName);
        try {
            //Copy the input file to the output file
            if(copyFile(inputPath, outputPath)) {
                //The file has been successfully copied
                //Exit the application
                System.exit(0);
            }
        } catch (IOException e) { e.printStackTrace(); return; }
    }

    //Is the external storage ready?
    public boolean isExternalReady() {
        //Get the current state of the external storage
        //Check if the state retrieved is equal to MOUNTED
        Boolean isMounted = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
        if(isMounted) {
            //The external storage is ready
            return true;
        }
        //The external storage is not ready
        return false;
    }

    //Get the data dir of a specific app if it exists
    public ApplicationInfo getPackageInfo(String packageName) throws PackageNotFoundException {
        List<ApplicationInfo> packages;
        PackageManager pm;
        //Init the package manager as pm
        pm = getPackageManager();
        //Get all installed applications
        packages = pm.getInstalledApplications(0);
        //Get the ApplicationInfo as packageInfo from each packages
        for(ApplicationInfo packageInfo:packages) {
            //Check for a name that matches the packageName
            if(packageInfo.packageName.equals(packageName)) {
                //The package exists
                return packageInfo;
            }
        }
        //The package was not found
        //Throw an exception
        throw new PackageNotFoundException("Package not found");
    }

    //Copy a file from an input directory to an output directory
    public boolean copyFile(String inputPath, String outputPath) throws IOException {
        //Construct the input and output paths as File objects with respective read/write privileges
        //File inputFile = new File("/data/data/org.xbmc.xbmc/files/.xbmc/userdata/guisettings.bak");
        //File outputFile = new File("/data/data/org.xbmc.xbmc/files/.xbmc/userdata/guisettings.xml");
        //File inputFile = getDir(inputPath, MODE_PRIVATE);
        //File outputFile = getDir(outputPath, MODE_PRIVATE);
        File inputFile = new File(inputPath);
        File outputFile = new File(outputPath);
        //Check if the input and output files exist
        if(!inputFile.exists()) {
            return false;
        }
        if(!outputFile.exists()) {
            //Create the output file
            new File(outputPath);
        }
        //Get the input read state
        boolean canReadInput = inputFile.canRead();
        //Get the output write state
        boolean canWriteOutput = outputFile.canWrite();
        //Check if the input file can be read and if the output file can be written
        if(canReadInput && canWriteOutput) {
            //Open respective input and output buffer streams
            InputStream in = new FileInputStream(inputFile);
            OutputStream out = new FileOutputStream(outputFile);
            //Create a byte array
            byte[] buffer = new byte[1024];
            //The current position of the byte buffer
            int bufferPosition;
            //While the bufferPosition is reading the file 1024 bytes at a time (-1 = no longer reading)
            while((bufferPosition = in.read(buffer)) != -1) {
                //Append the current buffer in memory to the output file
                //With a pointer offset of 0 and a count of the current bufferPosition
                out.write(buffer, 0, bufferPosition);
            }
            //Close the file streams
            in.close();
            out.close();
            return true;
        }
        return false;
    }

    //The Package Error Class
    private class PackageNotFoundException extends Exception {
        //If an error is thrown with a message parameter
        PackageNotFoundException(String m) {
            //Pass the message to the super Exception class
            super(m);
        }
    }
}

Solution

  • It turns out that my android device was having some issues connecting to my computer, hence the CIP Error.

    After switching to another device, I also discovered that the input file itself was not being found, as I was trying to access the it through the "data/data" directory. The app data directories for installed apps can only be accessed through the external storage path. Since this varies from device to device, it needs to be retrieved dynamically.

    Environment.getExternalStorageDirectory().getAbsolutePath();
    

    After accessing the file this way I was able to successfully copy it.