From Android 11, scoped storage must be used.
How do I create a zip file with my app, which is then saved in e.g. Documents?
The .txt. Files to be zipped are in the internal app storage
I can create zip files, but I can't manage the zip file via "Scoped Storage" in the
save to the public "Downloads" folder.
Would be grateful for any help...
Regards
Herman
#Override
public void onClick(View v) {
String dateiname="Backup.zip";
Intent intentm = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intentm.addCategory(Intent.CATEGORY_OPENABLE);
intentm.setType("application/zip");
intentm.putExtra(Intent.EXTRA_TITLE, dateiname);
someActivityResultLauncher.launch(intentm);
}
private void createDocument(Uri uri) throws FileNotFoundException {
getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
String inputPath1 = getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath();
String inputFile = "Backup_Stromverbrauch.zip";
String pfad1 = getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS).toString();
String []s=new String[1];//String Array, Anzahl Dateien z
s[0] = inputPath1 + "/Test.txt";
String xxx= String.valueOf(Uri.parse(uri.toString()));
Toast.makeText(MainActivity.this, xxx, Toast.LENGTH_LONG).show();
try {
ParcelFileDescriptor fileDescriptor = this.getContentResolver().openFileDescriptor(uri, "w");
FileOutputStream fileOutputStream =
new FileOutputStream(fileDescriptor.getFileDescriptor());
ZipManager zipManager = new ZipManager();
zipManager.zip(s, String.valueOf(fileOutputStream));
} catch (Exception e) {
}
Related
My app should save files to a place where, when you connect your phone/tablet to a computer, you can see them through the system file explorer.
This is the way I implemented file writing:
protected String mDir = Environment.DIRECTORY_DOCUMENTS;
protected File mPath = Environment.getExternalStoragePublicDirectory(mDir);
protected void writeLogFile(String filename) {
File f = new File(mPath, filename + ".txt");
f.getParentFile().mkdirs();
try (BufferedWriter bw = new BufferedWriter(new FileWriter(f, false))) {
// Details omitted.
} catch (Exception e) {
e.printStackTrace();
return;
}
makeText("Wrote " + f.getAbsolutePath());
}
This is what I see when I connect my Sony Xperia Z4 tablet to Windows (notice missing documents folder):
This is the directory to which the file is written (using above implementation):
What is wrong with my implementation?
What is wrong with my implementation?
MediaStore has not discovered your newly-created files yet. What you see in Windows — and in many on-device "gallery" apps — is based on what MediaStore has indexed.
Use MediaScannerConnection and its scanFile() method to tell MediaStore about your file, once you have written out your data to disk:
public void scanFile(Context ctxt, File f, String mimeType) {
MediaScannerConnection
.scanFile(ctxt, new String[] {f.getAbsolutePath()},
new String[] {mimeType}, null);
}
or, in Kotlin:
fun scanFile(ctxt: Context, f: File, mimeType: String) {
MediaScannerConnection.scanFile(ctxt, arrayOf(f.getAbsolutePath()), arrayOf(mimeType), null)
}
My app should save files to a place where, when you connect your phone/tablet to a computer, you can see them through the system file explorer.
This is the way I implemented file writing:
protected String mDir = Environment.DIRECTORY_DOCUMENTS;
protected File mPath = Environment.getExternalStoragePublicDirectory(mDir);
protected void writeLogFile(String filename) {
File f = new File(mPath, filename + ".txt");
f.getParentFile().mkdirs();
try (BufferedWriter bw = new BufferedWriter(new FileWriter(f, false))) {
// Details omitted.
} catch (Exception e) {
e.printStackTrace();
return;
}
makeText("Wrote " + f.getAbsolutePath());
}
This is what I see when I connect my Sony Xperia Z4 tablet to Windows (notice missing documents folder):
This is the directory to which the file is written (using above implementation):
What is wrong with my implementation?
What is wrong with my implementation?
MediaStore has not discovered your newly-created files yet. What you see in Windows — and in many on-device "gallery" apps — is based on what MediaStore has indexed.
Use MediaScannerConnection and its scanFile() method to tell MediaStore about your file, once you have written out your data to disk:
public void scanFile(Context ctxt, File f, String mimeType) {
MediaScannerConnection
.scanFile(ctxt, new String[] {f.getAbsolutePath()},
new String[] {mimeType}, null);
}
or, in Kotlin:
fun scanFile(ctxt: Context, f: File, mimeType: String) {
MediaScannerConnection.scanFile(ctxt, arrayOf(f.getAbsolutePath()), arrayOf(mimeType), null)
}
I want to create a XML file inside my Android app.
This file I want to write into the documents folder of my Android device.
Later I want to connect my Android device to my PC using USB and read that XML file out of the documents folder.
My Device is an Android Galaxy Tab Pro 10.1, Android 4.4.2.
I tried already:
String fileName = "example.xml";
String myDirectory = "myDirectory";
String externalStorage = Environment.getExternalStorageDirectory().getAbsolutePath();
File outputFile = new File(externalStorage + File.separator + myDirectory + File.separator + fileName);
But no file is created. I also want later to read that file out of the documents folder into may app again.
Any help is appreciated, thanks!
I know this is late, but you can get the documents directory like this:
File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS);
File file = new File(dir, "example.txt");
//Write to file
try (FileWriter fileWriter = new FileWriter(file)) {
fileWriter.append("Writing to file!");
} catch (IOException e) {
//Handle exception
}
Set permission in Android Manifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Use this code to write to external directory
String fileName = "example.xml";
String dirName = "MyDirectory";
String contentToWrite = "Your Content Goes Here";
File myDir = new File("sdcard", dirName);
/*if directory doesn't exist, create it*/
if(!myDir.exists())
myDir.mkdirs();
File myFile = new File(myDir, fileName);
/*Write to file*/
try {
FileWriter fileWriter = new FileWriter(myFile);
fileWriter.append(contentToWrite);
fileWriter.flush();
fileWriter.close();
}
catch(IOException e){
e.printStackTrace();
}
Before creating file you have to create directory in which you are saving the file.
Try like this one:-
String fileName = "example.xml";
String myDirectory = "myDirectory";
String externalStorage = Environment.getExternalStorageDirectory().getAbsolutePath();
File outputDirectory = new File(externalStorage + File.separator + myDirectory );
if(!outputDirectory.exist()){
outputDirectory.mkDir();
}
File outputFile = new File(externalStorage + File.separator + myDirectory + File.separator + fileName);
outputFile.createFile();
Try restarting you device and then check if the file exists. If so, you are creating it (which it looks like you should be based on your code) but it is not showing up until the media is scanned on your device. Try implementing MediaScannerConnectionClient so it will show become visible after creation.
public class MainActivity extends Activity implements MediaScannerConnectionClient {
private MediaScannerConnection msConn;
private File example;
...
#Override
protected void onCreate(Bundle savedInstanceState) {
...
msConn = new MediaScannerConnection(this.getApplicationContext(), this);
String dir = Environment.getExternalStorageDirectory() + "/Documents/";
example = new File(dir, "example.xml");
msConn.connect();
}
#Override
public void onMediaScannerConnected() {
msConn.scanFile(example.getAbsolutePath(), null);
}
#Override
public void onScanCompleted(String path, Uri uri) {
msConn.disconnect();
}
From Android 10 onwards, Android started using Scoped Storage model to protect user privacy.
If you want to share this file with the User, then you should write this file in Shared Storage. To write a file in Shared Storage, this has to be done in 3 steps:-
Step 1: Launch System Picker to choose the destination by the user. This will return Uri of the destination directory.
private ActivityResultLauncher<Intent> launcher; // Initialise this object in Activity.onCreate()
private Uri baseDocumentTreeUri;
public void launchBaseDirectoryPicker() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
launcher.launch(intent);
}
Step 2: Launch System Picker to choose the destination by the user. This will return the Uri of the destination directory. Also, you can optionally persist the permissions and Uri for future use.
#Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
baseDocumentTreeUri = Objects.requireNonNull(result.getData()).getData();
final int takeFlags = (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// take persistable Uri Permission for future use
context.getContentResolver().takePersistableUriPermission(result.getData().getData(), takeFlags);
SharedPreferences preferences = context.getSharedPreferences("com.example.fileutility", Context.MODE_PRIVATE);
preferences.edit().putString("filestorageuri", result.getData().getData().toString()).apply();
} else {
Log.e("FileUtility", "Some Error Occurred : " + result);
}
}
Step 3: Write CSV content into a file.
public void writeFile(String fileName, String content) {
try {
DocumentFile directory = DocumentFile.fromTreeUri(context, baseDocumentTreeUri);
DocumentFile file = directory.createFile("text/*", fileName);
ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(file.getUri(), "w");
FileOutputStream fos = new FileOutputStream(pfd.getFileDescriptor());
fos.write(content.getBytes());
fos.close();
} catch (IOException e) {
}
}
For more explanation, you can read "How to Save a file in Shared Storage in Android 10 or Higher" or Android official documentation.
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);
}
}
}
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.
ey up. ive built a simple music app that reads wav files from the sdcard and plays them.
how do i access the default media directory?
this is how i get the sdcard
public void LoadSounds() throws IOException
{
String extState = Environment.getExternalStorageState();
if(!extState.equals(Environment.MEDIA_MOUNTED)) {
//handle error here
}
else {
File sd = new File(Environment.getExternalStorageDirectory ()); //this needs to be a folder the user can access, like media
as usual the docs dont give an actual example of usage but it says this - If you're using API Level 8 or greater, use getExternalFilesDir() to open a File that represents the external storage directory where you should save your files. This method takes a type parameter that specifies the type of subdirectory you want, such as DIRECTORY_MUSIC...
how do i use it?
thank you
edit:
this makes it crash if i try to fill a spinner array with file path Strings.
File path = getExternalFilesDir(Environment.DIRECTORY_MUSIC);
File sd = new File(path, "/myFolder");
File[] sdDirList = sd.listFiles(new WavFilter());
if (sdDirList != null)
{
//sort the spinner
amountofiles = sdDirList.length;
array_spinner=new String[amountofiles];
......
final Spinner s = (Spinner) findViewById(R.id.spinner1); //crashes here
ArrayAdapter<?> adapter = new ArrayAdapter<Object>(this,
android.R.layout.select_dialog_item, array_spinner);
EDIT2:
ok so ive done this test that is supposed to write a txt file to the music directory.
i run the app, no txt file is written anywhere on the device i can find.
// Path to write files to
String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getAbsolutePath();
String fname = "mytest.txt";
// Current state of the external media
String extState = Environment.getExternalStorageState();
// External media can be written onto
if (extState.equals(Environment.MEDIA_MOUNTED))
{
try {
// Make sure the path exists
boolean exists = (new File(path)).exists();
if (!exists){ new File(path).mkdirs(); }
// Open output stream
FileOutputStream fOut = new FileOutputStream(path + fname);
fOut.write("Test".getBytes());
// Close output stream
fOut.flush();
fOut.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
another edit: i will get this working!!
so if i use this line it creates a folder on the sdcard called 'Musictest'. dont understand??
String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC + "test").getAbsolutePath();
////////////////////////////////////////////////////////////////////
Final Edit:
right so this will look for a folder called test in the devices music directory.
if it doesnt exist, it will be created.
(some fixing to be done here, error if empty) it then lists the files in the directory and adds them to an array.
public void LoadSounds() throws IOException
{
String extState = Environment.getExternalStorageState();
// Path to write files to
String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC + "/test").getAbsolutePath();
if(!extState.equals(Environment.MEDIA_MOUNTED)) {
//handle error here
}
else {
//do your file work here
// Make sure the path exists
boolean exists = (new File(path)).exists();
//if not create it
if (!exists){ new File(path).mkdirs(); }
File sd = new File(path);
//This will return an array with all the Files (directories and files)
//in the external storage folder
File[] sdDirList = sd.listFiles();
if (sdDirList != null)
{
//add the files to the spinner array
array_spinnerLoad=new String[sdDirList.length];
files = new String[sdDirList.length];
for(int i=0;i<sdDirList.length;i++){
array_spinnerLoad[i] = sdDirList[i].getName();
files[i] = sdDirList[i].getAbsolutePath();
}
}
}
}
as mentioned in the docs, getExternalFilesDir() return File. And File object can represent either file or directory.
Therefore:
File musicDirectory = new File( getExternalFilesDir(Environment.DIRECTORY_MUSIC));
Will give you the object to play with.