I am working on an app which moves a file from sdcard to internal memory storage .What I need is :
1.To detect the size of the file to be moved.
2.Detect the size of free memory in internal storage.
3.Compare both?
This would give some alert whenever the free memory is less than the size of the file.
How can I do the first two points.If anyone worked on similar type of problem?
long file_size = file.length();
File data_path = Environment.getDataDirectory();
StatFs stat = new StatFs(data_path.getPath());
long free_internal_memory = stat.getBlockSize() * stat.getAvailableBlocks();
I've done something similar, but then for multiple (music) files in a directory, and across any mount point available to the system. I'm not 100% sure the explanation below will be applicable for the internal storage, but it should at least give you some useful pointers.
You can easily get the size of a file by calling .length() on it:
long fileSize = someFile.length();
Note that in case someFile is actually a directory, the result is not defined. Hence, to get a directory's size, iterate over all its children (which on its turn may again contain directories of course).
For retrieving information about the file system's space, I used the statFs class, which is nothing more but a Java wrapper for statfs(). Calculating the available space is a simple multiplication:
// 'fromFreeBytes' is the source file/directory size
StatFs toDirStats = new StatFs(mToDir.getAbsolutePath());
long toFreeBytes = ((long)toDirStats.getAvailableBlocks() * (long)toDirStats.getBlockSize());
if (toFreeBytes < fromFreeBytes) {
//insufficient available space
}
Finally, it's important to remember that if you're going to move files between different mount points, you cannot use File's renameTo(...) method. In stead you'll have to use an InputStream and OutputStream to copy the data across.
Good luck!
Related
I have two parts to this question: 1) what is the best solution to my need, and 2) how do I do this?
1) I have a client app which sends bundles to a service app. the bundles can break the limit on bundle size, so I need to write the actual request out and read it in on the service side. Because of this, I can't write to my private internal storage. I've used these pages heavily, and haven't had luck: http://developer.android.com/guide/topics/data/data-storage.html
http://developer.android.com/training/basics/data-storage/files.html
My current understanding is that my best path is to use this to get a public dir:
File innerDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
I then add in my filename:
String fileName = String.valueOf(request.timestamp + "_avoidRoute"+count+++".ggr");
Combing these two results in the full file path:
/storage/emulated/0/Download/GroundGuidance/Route/1425579692169_avoidRoute1.ggr
Which I write to disk like this:
fos = context.openFileOutput(fullPath, Context.MODE_WORLD_WRITEABLE);
fos.write(routeString.getBytes());
fos.close();
When I try to write this to disk I get the error
java.lang.IllegalArgumentException: File /storage/emulated/0/Download/GroundGuidance/Route/1425579692169_avoidRoute1.ggr contains a path separator
Of course it does - I need it to have a path. I've searched online for solutions to this error which tell me to us FileOutputStream to write a full path. I did, but while my app doesn't error and appears to create the file, I'm also not able to view it on my phone in Windows Explorer, leading me to believe that it is creating a file with private permissions. So this brings me to my post and two questions:
1) Is there a different approach I should be trying to take to share large amounts of data between my client and service apps?
2) If not, what am I missing?
Thanks all for reading and trying to help!
Combing these two results in the full file path:
/storage/emulated/0/Download/GroundGuidance/Route/1425579692169_avoidRoute1.ggr
Which I write to disk like this:
fos = context.openFileOutput(fullPath, Context.MODE_WORLD_WRITEABLE);
This is not an appropriate use of Context's openFileOutput() method as that does not take a full path, but rather a filename within an app's private storage area.
If you are going to develop a full path yourself, as you have, then use
fos = new FileOutputStream(fullPath)
The Sharing permission setting is not applicable to the External Storage, though you will need a manifest permission to write (and implicitly read) on your creator, and the one for reading on your consumer.
Or, instead of constructing a full path, you could use your private storage with a filename and Context.MODE_WORLD_WRITEABLE (despite the being deprecated as an advisory) and pass the absolute path of the result to the other app to use with new FileInputStream(path).
Or you could use any of the other data interchange methods - content providers, local sockets, etc.
I'm trying to find a way to find the total size and free space of a mounted SD card on a phone, from my research on SOF and on the Android devs site I was able to find the method getExternalStorageDirectory() but according to the Android API this returns a directory that is not necessarily external:
"Traditionally this is an SD card, but it may also be implemented as built-in storage in a device that is distinct from the protected internal storage and can be mounted as a filesystem on a computer."
So I gather from the way that is worded that the "external storage" directory can actually be apart of multiple physical storage devices (internal and external memory). And from my testing that's what I've found as the size that is being returned by using this method is around 1.5x the size of my actual SD card.
So my question is, is there a programmatical way to return the total size and available space just on the SD card? The phone itself can give me that information so I feel like there should be a way but I'm at a loss right now... any help would be appreciated!
EDIT:
This is the code I'm currently using for total size
private long TotalSDMemory(){
File path = Environment.getExternalStorageDirectory();
StatFs stat = new StatFs(path.getAbsolutePath());
long blockSize = stat.getBlockSize();
long totalBlocks = stat.getBlockCount();
long totalSpace = totalBlocks * blockSize;
Log.d(TAG,"Size of total SD Memory: "+totalSpace);
Log.d(TAG, "External storage emulated: "+Environment.isExternalStorageEmulated());
return totalSpace;
}
Edit(2):
I didn't know this mattered but I have a Samsung Galaxy S3 which is what I am using to test the code, apparently Samsung has a different file structure for their external memory. Here is a link that should help anyone else get the correct size:
Get size of SD card in Samsung phones
public String[] getSize() throws IOException {
String memory="";
Process p = Runtime.getRuntime().exec("df /mnt/sdcard");
InputStream is =p.getInputStream();
int by=-1;
while((by=is.read())!=-1) {
memory+=new String(new byte[]{(byte)by});
}
for (String df:memory.split("/n")) {
if(df.startsWith("/mnt/sdcard")) {
String[] par = df.split(" ");
List<String> pp=new ArrayList<String>();
for(String pa:par) {
if(!pa.isEmpty()) {
pp.add(pa);
}
}
return pp.toArray(new String[pp.size()]);
}
}
return null;
}
getSize()[0] is /mnt/sdcard. getSize()[1] is size of sd (example 12.0G), getSize()[2] is used, [3] is free, [4] is blksize
Or:
new File("/sdcard/").getFreeSpace() - bytes of free in long
new File("/sdcard/").getTotalSpace() - size of sd
Yes, there is a way.
StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
long sdAvailSize = (long)stat.getAvailableBlocks()
* (long)stat.getBlockSize();
//One binary gigabyte equals 1,073,741,824 bytes.
long gigaAvailable = sdAvailSize / 1073741824;
Got that from here: How can I check how much free space an SD card mounted on an Android device has?
Concerning your question about getting total size look here: Getting all the total and available space on Android
Edit:
Marcelo Filho has pointed out that this method is deprecated in API 18 (KitKat).
Google suggests to use getAvailableBlocksLong () and getBlockCountLong () instead. Both methods will return a long value and not a double.
Hint:
Kikiwa has pointed out that the datatype long should be used with these -now deprecated - methods, otherwise you may get negative values if the filesize is too large.
I have android app which downloads files from google docs to SD card on device. (reason: have PDF-s which I cannot open within app).
It writes successfully to SD card until I get to ~8000th file of 10000 total.
Code for writing to SD:
InputStream is = response.getContent();
FileOutputStream fos = new FileOutputStream(new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/"+preferences.getString("username", "manas11")+"/" + tmp_entry.resourceID.replace(":","~_~")+"~_~"+tmp_entry.title));
byte[] buf = new byte[1024];
int len;
while((len=is.read(buf))>0)
fos.write(buf,0,len);
Exception thrown by line 2:
java.io.FileNotFoundException: /mnt/sdcard/matulic.realestate.hr/file~_~0B3n2EnTf5ATnYTJkNTNmM2QtZDJjYy00YjNhLWJlZjQtYTE4MTU5MjI2N2E5~_~Kuæa Marina Sevid 399.00 m2 - LJETNA AKCIJA IZVRSN - k359.txt (No space left on device)
SD card is microSD™ memory card (SD 2.0 compatible), 8gb, FAT32 formatted. Im using Desire HD.
As you can see filenames are long.
I save files to directory in /mnt/sdcard/ which state after exception is (by Astro):
size: 519,668,573 bytes
number of files: 8037
device free size: 4.91 G
Is there any limit for writing to SD I dont know about?
Thank you
I believe this stackoverflow question will answer your question.
Is there a limit for the number of files in a directory on an SD card?
I also checked out some of the information myself and found it basically comes down to a limit in the number of files and the length of the file name. From what I read in the Microsoft document referenced in the link above http://msdn.microsoft.com/en-us/windows/hardware/gg463080.aspx you have a problem with the length of your file names.
First is the length of your file names. Longer file names take up more space. There is a limit of 65,536 32 byte entries in the directory. This is because the maximum size of a directory file container is 2,097,152 bytes (65536*32). However, if your file names are longer than 8.3 they will take up more than just one entry. Also long file names take up more space than simply the sum of their characters. There is overhead to the filesystem that creates things like checksums and a short 8.3 file name to go along with it.
Best advice would be to shorten the file names dramatically and that should solve your problem.
Hope this helps.
It might be a limitation of FAT32.
A FAT32 directory can have 65,536 directory entries. Each file and
subdirectory takes from two to thirteen entries, depending on the
length of its name, so those entries can disappear long before you
think you've used them all up. Your total of 22,657 files could very
easily use 65,000 entries.
From here.
Have you tried reducing the file name when storing it locally? Does it really have to be that long?
I'm developing an Android 2.2 application.
I want to add some big text files (4.5MB or more) to Android project.
First I don't know if I can add such kind of big files to assets folder. But, if I can, is it possible to compress them?
How can I compress files? and decompress?
Any other better way to add big text files to Android project?
Thanks.
Files over 1 MB placed in the assets folder won't be readable from your app (It'll throw an exception). This is because they get compressed during the build process, and thus the phone requires substantial resources to uncompress them when on the handset.
I believe you can place them in the raw folder, where they won't get compressed or use an extension that AAPT assumes is already compressed (see here)
However, It's not good having a 4.5 MB text file uncompressed sitting in the APK, It's wasted space that could be handled better. Try thinking about downloading the data on first use instead, or splitting the file into chunks as suggested before so that AAPT can compress it.
Another approach is you should copy your file into SD card during the first run using IOUtils. Here also be careful also because if you will copy each byte then more resources will be occupied.
It works for me, I needed to put 30MB large zip file into Assets folder because of Client's requirement.
You can, but sometimes it gives problems. You don't have to compress it, because the package itself is compressed (the .APK), in fact, anything that you store in the assets folder is uncompressed when you read it. With regards to the size of the file, you may want to cut it and put smaller parts of the file inside the assets folder.
I believe the assets directory (except for raw) is already compressed. Also the Android Market will soon/is allowing apks of 50MB in size. Try it first and then see if you have any problems.
You need to do fragmentation work for that 4.5 MB text file. Where you need to split the text file into five files with 1 MB maximum size. Then again you need to rejoin them like this:
OutputStream databaseOutputStream = new FileOutputStream(outFileName);
InputStream databaseInputStream;
byte[] buffer = new byte[1024];
int length;
databaseInputStream = myContext.getResources().openRawResource(
R.raw.outfileaaa);
while ((length = databaseInputStream.read(buffer)) > 0) {
databaseOutputStream.write(buffer);
}
databaseInputStream.close();
databaseInputStream = myContext.getResources().openRawResource(
R.raw.outfileaba);
while ((length = databaseInputStream.read(buffer)) > 0) {
databaseOutputStream.write(buffer);
}
databaseInputStream.close();
databaseOutputStream.flush();
databaseOutputStream.close();
I have an application which has a directory created into SDCard where I save photos. I would like to know how much space is using that dir on SDCard in order to show that info to the user.
I'm not sure if its the best solution but you could do something like that:
int totalSize = 0;
File root = new File("path to one of your file").getParentFile();
File[] files = root.listFiles();
for (File file: files) {
totalSize = totalSize + file.length();
}
Then totalSize contains the sum of all files in the directory in bytes. depending on the structure of your directory (e.g. are there any subdirectories?) you have to adapt the code.
Edit:
After a little bit of researching I'm almost sure that there is no method in java which directly returns the size of a directory. See e.g. this link:
http://forums.sun.com/thread.jspa?threadID=640296
However in this link http://www.codemiles.com/java/get-directory-size-in-java-t1242.html there is a recursive version of my code mentioned above to calculate any subdirectories if availiable.
There is also a small library which can do what you want:
http://commons.apache.org/io/api-release/index.html
However then you have to import this library. I personally would prefer to write this short method by myself.