简体   繁体   中英

File from InputStream

Yes, this question has been asked a millions times, and I believe I've looked at them all. They are very "sometimesy", slow, or not what I need.

On one project, I use the following code to use the InputStream received from a GET to turn that into a PDF. This works PERFECTLY, every time, on my physical device and my emulator (Genymotion 2.1.1, Emulator API 18 4.3). Note that some things are edited out, and the PDFs are generally small, less than 1 MB.

public abstract class MyPDFFile extends File implements ApiModel{

public MyPDFFile(InputStream inputStream){
    super(context.getExternalFilesDir(
            Environment.DIRECTORY_DOWNLOADS), "my_pdf.pdf");

    if (externalStorageIsWritable()) {
        try {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            FileOutputStream fileInputStream = new FileOutputStream(this);
            BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(fileInputStream));

            int readLine;
            char[] cbuf = new char[1];

            do {
                readLine = bufferedReader.read(cbuf);
                bufferedWriter.write(cbuf);
            } while (readLine != -1);
            bufferedWriter.close();
        }
        catch(IOException e){
            // Didn't work
        }
    }
    else{
        // Cant write
    }
} 

I figured on this new project, I could use the same code to download an APK from the internet to the device. Nope, definitely not the case. I eventually tried this for Inputstream to File:

FileOutputStream fileOutputStream = new FileOutputStream(file);

byte[] buffer = new byte[1];
while ( (read(buffer)) > 0 ) {

    fileOutputStream.write(buffer);
}
fileOutputStream.close();
close();

That works on my emulator, and works fine. I moved to testing on my device... not so much, which is weird, because the working PDF code works on both my emulator and device. I've tried adjusting the size of my buffer to various multiples of 512 (which results in the file being EXTREMELY small, like a few KB, to being EXTREMELY large, about double the apk size, which is about 5.6 MB).

Also, another weird thing: I can NEVER get it to successfully save outside of the constructor. When I do the saving there, the InputStream is fine, my file gets created, yadayada, and when I use successful code, I just rename the file afterwards since all I have access to in the constructor is the InputStream. If I decide "No, I want to name it when I have the proper things" and simply save the InputStream to my object, it NEVER works properly. Can never get above 4KB for the downloaded file. I've tried extends InputStream and extends BufferedInputStream to no avail.

I can post more code if needed. All I would have access to is the InputStream from my GET request; I'm using the browep Android HTTP library and that's all I can get without trying to mess with the library itself (or overriding methods in it).

The problem is that you're reading the file byte by byte. This can take ton of time. Instead, read the file in bigger piece of chunks, like 4 or 8 KBs:

int file_chunk_size = 1024 * 4; //4KBs, written like this to easily change it to 8
byte[] buffer = new byte[file_chunk_size];
int bytesRead = 0;
while ( (bytesRead = read(buffer)) > 0 ) {
    fileOutputStream.write(buffer, 0, bytesRead);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM