Java.io.File - Cannot rename and move file on Android - java

I can't rename/move my temporary file and open it
Here is the code I used to create the temporary file
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
//[...]
java.io.File tempFile = java.io.File.createTempFile("filetmp", "_handled", null);
FileOutputStream fos = new FileOutputStream(tempFile);
fos.write(responseBody); //responseBody (byte[]) not null
fos.close();
//[...]
}
Then, I (try to) save it on the disk
private void saveIntoDisk(java.io.File file) {
if (PersitencyManager.isExternalStorageWritable()) {
java.io.File dirEvent = this.getParentEvent().getDirectory();
Log.d("ROOT PATH", "" + dirEvent.getAbsolutePath());
java.io.File myNewFile = new java.io.File(dirEvent.toString() + "/"+identifiant+"_"+name);
Log.d("FILE PATH", "" + myNewFile.getAbsolutePath());
path = myNewFile.getAbsolutePath();
if (!file.renameTo(myNewFile)) {
Log.e("File Rename", "Can not rename this file"); // display on console
} else {
Log.i("File Rename", "Filed renamed successfully");
}
}
}
The way I create the parent folder :
public static java.io.File getFolderStorageDir(String folderName) {
// Get the directory for the user's public pictures directory.
java.io.File file = new java.io.File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOCUMENTS), folderName);
if (!file.mkdirs()) {
if (!file.isDirectory()) {
Log.e("Directory_Creation", "Directory not created");
}
}
return file;
}
I get this message on my console : "Can not rename this file". file.renameTo(myNewFile) does not work..
The path seems to be good :
D/FILE PATH﹕ /storage/emulated/0/Documents/12047/4691_test.pdf
Here is my AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Result : The parent folder is created but not the file ...
Any idea about my problem ?

I found the problem..
I can't rename a file with a path that is located on other storage zone.
renameTo() : Both paths be on the same mount point. On Android, applications are
most likely to hit this restriction when attempting to copy between
internal storage and an SD card.
When I created the temporary file, I give null at the directory parameter and as Google said
directory : [...]
null for the default location for temporary files, which is taken from
the "java.io.tmpdir" system property. [...]
So my temporary directory was on internal storage than the SD Card Directory.
So, I modified the directory :
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
//[...]
java.io.File dir = new java.io.File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOCUMENTS), folderName);
java.io.File tempFile = java.io.File.createTempFile("filetmp", "_handled", dir.getAbsolutePath());
FileOutputStream fos = new FileOutputStream(tempFile);
fos.write(responseBody); //responseBody (byte[]) not null
fos.close();
//[...]
}

Try instead of using a raw File constructor, use the method getFileStreamPath provided by the Context. That is to say, do:
File oldfile = ctx.getFileStreamPath("shoppinglists.tmp");
File newfile = ctx.getFileStreamPath("shoppinglists.csv");
oldFile.renameTo(newFile);
The problem is presumably that new File() refers to a name relative to the program's current directory, which is probably not, and certainly not guaranteed to be, the directory in which internal files are stored.
Rename a file in the internal storage

Related

How can you create a new zip file in Java and add a large directory of files to it?

I'm trying to add a directory of files to a zip. The directory is around 150 files large. A few, 5-75 files in, I keep getting a crash with the error message "The process cannot access the file because it is being used by another process."
I tried a delay which may be helping but is certainly not solving the bug.
Using code from:
Is it possible to create a NEW zip file using the java FileSystem?
final File folder = new File("C:/myDir/img");
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
continue;
}
else {
String filename = fileEntry.getName();
String toBeAddedName = "C:/myDir/img/" + filename;
Path toBeAdded = FileSystems.getDefault().getPath(toBeAddedName).toAbsolutePath();
createZip(zipLocation, toBeAdded, "./" + filename);
System.out.println("Added file " + ++count);
//Delay because 'file in use' bug
try { Thread.sleep(1000); } //1secs
catch (InterruptedException e) {}
}
}
public static void createZip(Path zipLocation, Path toBeAdded, String internalPath) throws Throwable {
Map<String, String> env = new HashMap<String, String>();
//Check if file exists.
env.put("create", String.valueOf(Files.notExists(zipLocation)));
//Use a zip filesystem URI
URI fileUri = zipLocation.toUri(); //Here
URI zipUri = new URI("jar:" + fileUri.getScheme(), fileUri.getPath(), null);
System.out.println(zipUri);
//URI uri = URI.create("jar:file:"+zipLocation); //Here creates the zip
//Try with resource
try (FileSystem zipfs = FileSystems.newFileSystem(zipUri, env)) {
//Create internal path in the zipfs
Path internalTargetPath = zipfs.getPath(internalPath);
//Create parent dir
Files.createDirectories(internalTargetPath.getParent());
//Copy a file into the zip file
Files.copy(toBeAdded, internalTargetPath, StandardCopyOption.REPLACE_EXISTING);
}
}
I can't promise this is the cause of your problem, but your code compresses files into a ZIP file in a strange, or at least inefficient, manner. Specifically, you're opening up a new FileSystem for each individual file you want to compress. I'm assuming you're doing it this way because that's what the Q&A you linked to does. However, that answer is only compressing one file whereas you want to compress multiple files at the same time. You should keep the FileSystem open for the entire duration of compressing your directory.
public static void compress(Path directory, int depth, Path zipArchiveFile) throws IOException {
var uri = URI.create("jar:" + zipArchiveFile.toUri());
var env = Map.of("create", Boolean.toString(Files.notExists(zipArchiveFile, NOFOLLOW_LINKS)));
try (var fs = FileSystems.newFileSystem(uri, env)) {
Files.walkFileTree(directory, Set.of(), depth, new SimpleFileVisitor<>() {
private final Path archiveRoot = fs.getRootDirectories().iterator().next();
#Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
// Don't include the directory itself
if (!directory.equals(dir)) {
Files.createDirectory(resolveDestination(dir));
}
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.copy(file, resolveDestination(file), REPLACE_EXISTING);
return FileVisitResult.CONTINUE;
}
private Path resolveDestination(Path path) {
/*
* Use Path#resolve(String) instead of Path#resolve(Path). I couldn't find where the
* documentation mentions this, but at least three implementations will throw a
* ProviderMismatchException if #resolve(Path) is invoked with a Path argument that
* belongs to a different provider (i.e. if the implementation types don't match).
*
* Note: Those three implementations, at least in OpenJDK 12.0.1, are the JRT, ZIP/JAR,
* and Windows file system providers (I don't have access to Linux's or Mac's provider
* source currently).
*/
return archiveRoot.resolve(directory.relativize(path).toString());
}
});
}
}
Note: The depth parameter is used in exactly the same way as maxDepth is in Files#walkFileTree.
Note: If you only ever care about the files in the directory itself (i.e. don't want to recursively traverse the file tree), then you can use Files#list(Path). Don't forget to close the Stream when finished with it.
It's possible that you opening and closing the FileSystem over and over is causing your problems, in which case the above should solve the issue.

Android app: How do I create a directory in the internal storage

I can't seem to be able to figure out how to create a directory/file through an android app to the internal storage. I have the following code:
public class Environment extends SurfaceView implements SurfaceHolder.Callback {
public static String FILE_PATH;
//other unimportant variables
public Environment(Conext context) {
super(context);
FILE_PATH = context.getFilesDir() + "/My Dir/";
File customDir = new File(FILE_PATH);
if(!customDir.exists())
System.out.println("created my dir: " + customDir.mkdir());
File test = new File(FILE_PATH + "testFile.txt");
try {
if(!test.exists())
System.out.println("created test: " + test.createNewFile());
} catch(Exception e) {
e.printStackTrace();
}
//other unimportant stuff
}
}
I then use ES File Explorer to see if it created the file and I don't see the directory/file anywhere despite it printing out "true" for the System.out.println() calls.
What am I doing wrong?
The path where you are creating file is in apps private location. Generally you can't access it from outside. It's actually created in apps data folder. However it seems you want to write in external folder.
To write in the external storage, you must request the WRITE_EXTERNAL_STORAGE permission in your manifest file:
<manifest ...>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
...
</manifest>
code:
String folder_main = "My Dir";
File f = new File(Environment.getExternalStorageDirectory(), folder_main);
if (!f.exists()) {
f.mkdirs();
}
File test = new File(f , "testFile.txt");
Here you will find how to you will create folder/file in external storage.
Save a File on External Storage
You can try with below:
ContextWrapper contextWrapper = new ContextWrapper(getApplicationContext());
File directory = contextWrapper.getDir(getFilesDir().getName(), Context.MODE_PRIVATE);
File file = new File(directory,”fileName”);
String data = “TEST DATA”;
FileOutputStream fos = new FileOutputStream(“fileName”, true); // save
fos.write(data.getBytes());
fos.close();
This will write file in Device's internal storage (/data/user/0/com.yourapp/)
Hope this helps!

Create a public folder in internal storage

Sorry for my English, but I want to write in this file because in my opinion is the best.
Now my problem:
I want to create a folder in Internal storage to share with 2 application.
In my app, I downloaded an Apk from my server and I run it.
Before I used external storage and everything worked.
Now I want to use the internal storage for users that don't have an external storage.
I use this:
String folderPath = getFilesDir() + "Dir"
but when i try to run the Apk, it doesn't work, and I can't find this folder on my phone.
Thank you..
From this post :
Correct way:
Create a File for your desired directory (e.g., File path=new
File(getFilesDir(),"myfolder");)
Call mkdirs() on that File to create the directory if it does not exist
Create a File for the output file (e.g., File mypath=new File(path,"myfile.txt");)
Use standard Java I/O to write to that File (e.g., using new BufferedWriter(new FileWriter(mypath)))
Enjoy.
Also to create public file I use :
/**
* Context.MODE_PRIVATE will create the file (or replace a file of the same name) and make it private to your application.
* Other modes available are: MODE_APPEND, MODE_WORLD_READABLE, and MODE_WORLD_WRITEABLE.
*/
public static void createInternalFile(Context theContext, String theFileName, byte[] theData, int theMode)
{
FileOutputStream fos = null;
try {
fos = theContext.openFileOutput(theFileName, theMode);
fos.write(theData);
fos.close();
} catch (FileNotFoundException e) {
Log.e(TAG, "[createInternalFile]" + e.getMessage());
} catch (IOException e) {
Log.e(TAG, "[createInternalFile]" + e.getMessage());
}
}
Just set theMode to MODE_WORLD_WRITEABLE or MODE_WORLD_READABLE (note they are deprecated from api lvl 17).
You can also use theContext.getDir(); but note what doc says :
Retrieve, creating if needed, a new directory in which the application can place its own custom data files. You can use the returned File object to create and access files in this directory. Note that files created through a File object will only be accessible by your own application; you can only set the mode of the entire directory, not of individual files.
Best wishes.
You can create a public into a existing system public folder, there is some public folder accessible from internal storage :
public static String DIRECTORY_MUSIC = "Music";
public static String DIRECTORY_PODCASTS = "Podcasts";
public static String DIRECTORY_RINGTONES = "Ringtones";
public static String DIRECTORY_ALARMS = "Alarms";
public static String DIRECTORY_NOTIFICATIONS = "Notifications";
public static String DIRECTORY_PICTURES = "Pictures";
public static String DIRECTORY_MOVIES = "Movies";
public static String DIRECTORY_DOWNLOADS = "Download";
public static String DIRECTORY_DCIM = "DCIM";
public static String DIRECTORY_DOCUMENTS = "Documents";
To create your folder, use this code :
File myDirectory = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "MyPublicFolder");
myDirectory.mkdir();
With this example, a public will be created in Documents and can be visible in any file's explorer app for Android.
try the below
File mydir = context.getDir("Newfolder", Context.MODE_PRIVATE); //Creating an internal dir;
if(!mydir.exists)
{
mydir.mkdirs();
}
This is what i have used and is working fine for me:
String extStorageDirectory = Environment.getExternalStorageDirectory().toString();
File file = new File(extStorageDirectory, fileName);
File parent=file.getParentFile();
if(!parent.exists()){
parent.mkdirs();
}
This will create a new directory if not already present or use the existing if already present.

How to open .gif file as InputStream from external storage on android

I am trying to load .gif image from external storage (pictures directory) but I am getting 'file not found exception' using the following code.
InputStream mInputStream = null;
AssetManager assetManager = getResources().getAssets();
try {
mInputStream = assetManager.open(getExternalFilesDir(Environment.DIRECTORY_PICTURES).getAbsolutePath().concat("/01.gif"));
} catch (IOException e) {
e.printStackTrace();
}
I have also tested using manually path but got same exception
mInputStream = assetManager.open("file:///mnt/sdcard/Android/data/com.shurjo.downloader/files/Pictures/01.gif");
There is a write/read permission from the SD card in menifest file
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Please help me how can I open a file as InputStream from external storage. Thanks in advance.
Note: I have tested it on emulator and there is a file 01.gif under Pictures folder (please see manual path). I can create directories and put files in those directories but can not able to access those files though Input Stream.
AssetManager is for accessing the files in the assets folder of the application package. It cannot be used to access files in the external storage.
You can use the following:
final String TAG = "MyAppTag";
File picturesDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File imageFile = null;
final int readLimit = 16 * 1024;
if(picturesDir != null){
imageFile = new File(picturesDir, "01.gif");
} else {
Log.w(TAG, "DIRECTORY_PICTURES is not available!");
}
if(imageFile != null){
mInputStream = new BufferedInputStream(new FileInputStream(imageFile), readLimit);
mInputStream.mark(readLimit);
} else {
Log.w(TAG, "GIF image is not available!");
}
Please also take a look at the sample code available in getExternalFilesDir
Update from : this

Include local .json file in Eclipse Android project

I have a local .json file. I don't want it to be on a server, I just want it to be included in my app. I tried to paste it directly into Eclipse in my project, but I got a FileNotFoundException, I also tried to paste it in the workspace folder in Windows Explorer/Finder and got the same exception. Where should I put it?
Thanks!
You should put the file either in the /assets or /res/raw directory of your Android project. From there, you can retrieve it with either: Context.getResources().openRawResource(R.raw.filename) or Context.getResources().getAssets().open("filename").
Put the json file in assets folder, I have used this method like this
public static String jsonToStringFromAssetFolder(String fileName,Context context) throws IOException {
AssetManager manager = context.getAssets();
InputStream file = manager.open(fileName);
byte[] data = new byte[file.available()];
file.read(data);
file.close();
return new String(data);
}
While parsing we can use the method like:
String jsondata= jsonToStringFromAssetFolder(your_filename, your_context);
jsonFileToJavaObjectsParsing(jsondata); // json data to java objects implementation
More Info: Prativa's Blog
Put the file in the assets folder.
You can use the AssetManager open(String fileName) to read the file.
Under /assets in your project folder. If you don't have one, make it.
Copy Asset to Local Storage
I had a very similar need. I had a label template file that I needed to provide a Bluetooth printer configuration so I included it in my assets directory and copied it to the internal storage for later use:
private static final String LABEL_TEMPLATE_FILE_NAME = "RJ_4030_4x3_labels.bin";
InputStream inputStreamOfLabelTemplate = getAssets().open( LABEL_TEMPLATE_ASSET_PATH );
labelTemplateFile = new File( getFilesDir() + LABEL_TEMPLATE_FILE_NAME );
copyInputStreamToFile( inputStreamOfLabelTemplate, labelTemplateFile );
printer.setCustomPaper( labelTemplateFile.getAbsolutePath() );
copyInputStreamToFile Function
// Copy an InputStream to a File.
//
private void copyInputStreamToFile(InputStream in, File file) {
try {
OutputStream out = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len;
while((len=in.read(buf))>0){
out.write(buf,0,len);
}
out.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}

Categories