Writing files to external storage in Android failing - java

As the title points out, I'm having trouble writing files to the external storage. My debug device is a Nexus 5. The thing is, I'm able to read files perfectly from the device (I've been trying with the ones in the Download Folder) but cannot write them. I am aware that I must do this while the device isn't connected to the computer. But it doesn't work either.
In fact, I've tried reading the state of the SD card prior to writing to it (which didn't work, of course). The state showed as "mounted" either when the device was connected to my PC or not. And I compared the state to Environment.MEDIA_MOUNTED_READ_ONLY and Environment.MEDIA_MOUNTED without any success. My device is in none of these states.
One thing which you must know is that my phone doesn't have an external SD card, as it's an internal one. This results in my device having a "/storage/emulated/0/..." directory for the external storage.
I must also point out that I have implemented the following tags in my Android Manifest:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="ANDROID.PERMISSION.WRITE_EXTERNAL_STORAGE"/>
I don't have any clue to what might be happening. Another thing which might help is that I've tried managing files with winrar (for Android) and I've been able to remove files with the device connected to my PC as well as without having it connected. So I don't know what to do.
The code which I'm using to write a file is the following. Bear in mind that it should read an image file (which it does), convert it into a string, convert it back into an image and then save it to the Downloads Folder:
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + "/base_image.jpg");
// Reading a Image file from file system
FileInputStream imageInFile = new FileInputStream(file);
byte imageData[] = new byte[(int) file.length()];
imageInFile.read(imageData);
// Converting Image byte array into Base64 String
String imageDataString = encodeImage(imageData);
// Converting a Base64 String into Image byte array
byte[] imageByteArray = decodeImage(imageDataString);
File newFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "converted_image.jpg");
//Write a image byte array into file system
FileOutputStream imageOutFile = new FileOutputStream(newFile);
imageOutFile.write(imageByteArray);
imageInFile.close();
imageOutFile.close();
What should I do?

Just fix ANDROID.PERMISSION.WRITE_EXTERNAL_STORAGE to android.permission.WRITE_EXTERNAL_STORAGE in your uses-permission.
I've encounterd this problem, UPPERCASE in permission is not useful.

FileOutputStream does NOT automatically create a file if it's not exist.
So, you need to check and create if your file doesn't exist.
if(!newFile.exists()) {
newFile.createNewFile();
}
Hope this help!

Related

java.io.File.length() greater than 0 when actual file is 0 bytes

What:
My Android application is compressing a directory on rooted Android Devices (API 25+) and writing the zip to a removable USB stick.
Problem:
Java is telling my that the file is 97,993 bytes but when I take the USB stick out of the Android Device and plug it into my mac, mac is saying it's 0 bytes.
Code:
/// Where is the directory that we're compressing onto the USB stick?
File dir = new File(Environment.getExternalStorageDirectory(), "logs");
if (!dir.exists() || !dir.isDirectory()) throw new IOException("Invalid directory.");
/// Where on the USB stick is the logs.zip going to go?
File zip = new File("/storage/FD91-1317/logs.zip");
/// Delete the file if it already exists then recreate it
if (zip.exists() && !zip.delete()) throw new IOException("Failed to create zip file.");
zip.createNewFile();
/// Using try {} to manage our streams
try (FileOutputStream fileOutputStream = new FileOutputStream(zip); ZipOutputStream zipOutputStream = new ZipOutputStream(fileOutputStream)) {
/// Get the list of files to enumerate through
File[] files = dir.listFiles();
// Enumerate through each file to be compressed
for (File file : files) {
/// If somehow a file was deleted throw an exception
if (!file.exists()) throw new FileNotFoundException(file.getPath());
/// Create the new zip entry
zipOutputStream.putNextEntry(new ZipEntry(file.getName()));
/// Copy the file into the zip
try (FileInputStream fileInputStream = new FileInputStream(file)) {
IOUtils.copy(fileInputStream, zipOutputStream);
}
/// Close the zip entry
zipOutputStream.closeEntry();
}
}
/// Validate that the zip has been created successfully
if (zip.length() == 0) throw new IOException("Zip failed to be created!!!!");
Log.v("logs", String.format("Logs collected: %s", zip.length());
More Info:
My application is running as a system app in the /system/priv-app/ directory
My application has the android.permission.WRITE_MEDIA_STORAGE permission
The zip file on the USB stick is only 0 bytes when plugged into the mac, if I remove the USB stick within 5-10 seconds after Log.v(...) is called. If I wait longer than 10 seconds it'll always have bytes.
Log.v(...) also is logging Logs collected: 97993
org.apache.commons.io.FileUtils.readFileToByteArray(zip) is also returning a byte array with the length of 97993 and the byte array 100% has data in it and isn't empty.
ls -l /storage/FD91-1317 is also saying that logs.zip is 97993 bytes.
Closing:
I've tried literally everything I can think of at this point but still can't figure out why Java is saying that the zip contains data but when plugged into my mac it's saying the file is 0 bytes. Windows is telling me the same thing. The only thing I know for a fact is that if I wait more than 10 seconds before removing the USB from my Android device, then this problem will not occur but I worry that depending on the size of the zip, that might not be enough time in all cases. To my knowledge, once you write to a stream and close it, it should be 100% completed.
In order to fix the issue, I had to run fileOutputStream.getFD().sync();
If anyone is wondering why running that had fixed it, here is a snippet from Java's docs to explain what sync(); does.
See: https://docs.oracle.com/javase/7/docs/api/java/io/FileDescriptor.html#sync() for more details.
Thanks so much to #CommonsWare for assisting!

How to access specific raw data on SD card?

I am doing an Android project. In this project i need to read the data of SD card sector by sector.I tried in some ways , Like
RandomAccessFile file = new RandomAccessFile("\\\\.\\PhysicalDrive0","r");
But Filenotfound Exception is coming. I did a similar kind of project in MFC(VC++). There by using Handle, CreateFile nad ReadFile functions i am reading the data sector wise. Any functions are there in java to read the data sector by sector ?
To read the SD card sector by sector, you'll need to run as root. I'd suggest something like the following:
Runtime.getRuntime().exec("su -c dd if=/dev/mmcblk1 of=/dev/stdout");
This should return a Process object whose standard output stream contains the data. The device name of the SD card may vary between different systems, and AFAIK there is no standardized way of finding out what it is, so you will have to experiment a little.
Good luck. :)
Jules is right if you read a block device,
however the internal storage in the new systems is mounted(exec mount on the device to check) on /mnt/shell/emulated(or smth like this) from /dev/fuse(using fuse daemon), which is not a block device but a character device( character special file), meaning that you cannot use random access to get data.
check out this, it might help.
You want to read data from sd card.So do something like this..
File dir = Environment.getExternalStorageDirectory();
File yourFile = new File(dir, "path_of_your_file");
And then you can read the file like..
fileInputStream = new FileInputStream(yourFile);
BufferedReader br = new BufferedReader(new InputStreamReader(fileInputStream));
String readString = new String();
while((readString = br.readLine())!= null){
//readString has your data
}

Editing existing file in Android

I am trying to edit existing file on the device by-First- select the file using selector that retrieve the path of the file like this "mnt/sdcard/file.png". Then I pass it to reader to read the existing file then modify it by by shifting the Ascii of every char. Then Overwrite it again to replace the old one.
I have tested the code on a desktop app on PC files and it Works perfect, but does not work as an Android app. It worked on my device once but did not work again
About what I did:
1)Add writing on External source Permission in the Mainafest file
2)Select the file right and retrieve it path
3)Read the file content true
File file = f;
FileInputStream fin;
fin = new FileInputStream(file);
byte fileContent[] = new byte[(int)file.length()];
fin.read(fileContent);
4)Modify the file bytes
5)Write back (Overwrite) in the original file
FileOutputStream fos = new FileOutputStream(f.getAbsolutePath());
fos.write(enc_msg);
fos.write((byte)seed);
fin.close();
fos.close();
6)Set the file to null again
7)Call finish() in the onClickListner
Thanks in Advance
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://" + Environment.getExternalStorageDirectory())));
However, the device must be disconnected from USB. Otherwise you need to unplug and replug the device to see the changes.
After a lot of work, I have reached the final solution by:
1)Using Common-io library
http://commons.apache.org/proper/commons-io/download_io.cgi
2)Writing this simple line only after import common-io
FileUtils.writeByteArrayToFile(new File(file.getAbsolutePath()), myByteArray, false);
the last attribute (Fasle) for overriding the file .. Append flag

error in sending image from android to java app serially -javax.imageio.IIOException: Bogus Huffman table definition

I need to send image from android app to java app. Basically, I need a byte array from the image to send to rf module which transmits.Another rf module receives and sends the byte array to java app which must make the image .
Android code:
FileInputStream fis = new FileInputStream(myFile);
byte[] b=new byte[(int)myFile.length()];
fis.read(b);server.send(b);
Java code:
FileOutputStream fwrite = new FileOutputStream(new File("my_xml"),true);
fwrite.write(bb);//bb is a byte from rf using input stream as soon as a byte comes it is read to file. This is necessary for some other reasons
fwrite.flush();
fwrite.close();
After getting full file:
FileInputStream fir=new FileInputStream("my_xml");
final BufferedImage bufferedImage = ImageIO.read(fir);
ImageIO.write(bufferedImage, "bmp", new File("image.bmp"));
fir.close();
I am getting error javax.imageio.IIOException: Bogus Huffman table definition
The rf is working fine because text file is being sent perfectly.Please help.Even without ImageIo code is not giving image even after changing extension to jpeg
The error means that the image file cant be read because the format is wrong.That is some bytes are missing or wrong or out of proper position and therefore file cant be decoded. My rf transfer does not have protocols like tcp/ip therefore some bytes are lost due to error in communication channel and hence the error.
You don't need to use ImageIO just to copy a file. Just read and write the bytes.
Your code has other problems:
You are assuming that read(byte[]) fills the buffer. It doesn't. Check the Javadoc.
You are also assuming that the file length fits into an int. If it does, fine. If it doesn't, you are hosed.
You appear to be opening and closing the FileOutputStream on every byte received. This could not be more inefficient. Open it once, write everything, close it.
flush() before close() is redundant.
You are storing the image in a file called 'my_xml'. This is only going to cause confusion, if it hasn't already.
You don't even need the file. Just load the image directly from the input stream.

Creating and reading a one time created file

I want to store a list of strings in a file.
I need to create it just one time, and after that i will read and write on it programmaticlly.
My question is where in the file system should i create the file (manually) so that it will best for reading and writing ?
Thanks.
You can create your file in your app's directory so no one can access it but your app
getApplicationContext().getFilesDir().getAbsolutePath();
or on sd card
File externalStorage = Environment.getExternalStorageDirectory();
if you want others to access it and, maybe, if your file is very big
If you intent to create your file manually then I think SD card is the only option unless you have a rooted phone or working with the emulator.
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
{
//SDcard is there
File f=new File("/sdcard/YOURFILE.txt");
if (!f.exists())
{
//File created only for first time
f.createNewFile();
//create inputstream and write it to your file
OutputStream out=new FileOutputStream(f);
byte buf[]=new byte[1024];
int len;
while((len=inputStream.read(buf))>0)
out.write(buf,0,len);
out.close();
inputStream.close();
System.out.println("\nData Written");
}
else { // read/ write SECOND TIME }
}
It really depends.
The problem with creating the file on the SDCard is that a special permission is required in order to access it. If the app is only for yourself, that's cool. If you want to distribute it through Google MarketPlay (or whatever it is called these days), please know that some people (myself included) tend to look at the permissions and ask "why would an app doing X require permission to do Y?", and sometimes not install the app because of it.
If the manual part is done by the app's user, by all means, store it on the sdcard. It's the only place a standard, none-root user even has access to.
Generally speaking, however, a better place to store data is in /data/data/packagename. See Android's data storage for more details.
Shachar
Add file in assets folder, then it will be clearly after new install

Categories