Getting the above error when trying to download large data using HttpGet
String uri = "";
getMethod = executeGet(uri);
httpClient.executeMethod(getMethod);
InputStream istream = getMethod.getResponseBodyAsStream();
byte[] data = IOUtils.toByteArray(istream);
FileUtils.writeByteArraytoFile(new File("xxx.zip"),data)
You are using a temporary byte array that might be the cause of the problem.
You can directly write the content of the stream to your file.
String uri = "";
getMethod = executeGet(uri);
httpClient.executeMethod(getMethod);
InputStream istream = getMethod.getResponseBodyAsStream();
IOUtils.copy(istream, new FileOutputStream(new File("xxx.zip"));
You're reading the entire response into the byte[] (memory). Instead, you could stream the output as you read it from istream with something like,
File f = new File("xxx.zip");
try (OutputStream os = new BufferedOutputStream(new FileOutputStream(f));) {
int c = -1;
while ((c = istream.read()) != -1) {
os.write(c);
}
} catch (Exception e) {
e.printStackTrace();
}
Related
I am trying to download a PDF file with HttpClient, it is downloading the PDF file but pages are blank. I can see the bytes on console from response if I print them. But when I try to write it to file it is producing a blank file.
FileUtils.writeByteArrayToFile(new File(outputFilePath), bytes);
However the file is showing correct size of 103KB and 297KB as expected but its just blank!!
I tried with Output stream as well like:
FileOutputStream fileOutputStream = new FileOutputStream(outFile);
fileOutputStream.write(bytes);
Also tried to write with UTF-8 coding like:
Writer out = new BufferedWriter( new OutputStreamWriter(
new FileOutputStream(outFile), "UTF-8"));
String str = new String(bytes, StandardCharsets.UTF_8);
try {
out.write(str);
} finally {
out.close();
}
Nothing is working for me. Any suggestion is highly appreciated..
Update: I am using DefaultHttpClient.
HttpGet httpget = new HttpGet(targetURI);
HttpResponse response = null;
String htmlContents = null;
try {
httpget = new HttpGet(url);
response = httpclient.execute(httpget);
InputStreamReader dataStream=new InputStreamReader(response.getEntity().getContent());
byte[] bytes = IOUtils.toByteArray(dataStream);
...
You do
InputStreamReader dataStream=new InputStreamReader(response.getEntity().getContent());
byte[] bytes = IOUtils.toByteArray(dataStream);
As has already been mentioned in comments, using a Reader class can damage binary data, e.g. PDF files. Thus, you should not wrap your content in an InputStreamReader.
As your content can be used to construct an InputStreamReader, though, I assume response.getEntity().getContent() returns an InputStream. Such an InputStream usually can be directly used as IOUtils.toByteArray argument.
So:
InputStream dataStream=response.getEntity().getContent();
byte[] bytes = IOUtils.toByteArray(dataStream);
should already work for you!
Here is a method I use to download a PDF file from a specific URL. The method requires two string arguments, an url string (example: "https://www.ibm.com/support/knowledgecenter/SSWRCJ_4.1.0/com.ibm.safos.doc_4.1/Planning_and_Installation.pdf") and a destination folder path to download the PDF file (or whatever) into. If the destination path does not exist within the local file system then it is automatically created:
public boolean downloadFile(String urlString, String destinationFolderPath) {
boolean result = false; // will turn to true if download is successful
if (!destinationFolderPath.endsWith("/") && !destinationFolderPath.endsWith("\\")) {
destinationFolderPath+= "/";
}
// If the destination path does not exist then create it.
File foldersToMake = new File(destinationFolderPath);
if (!foldersToMake.exists()) {
foldersToMake.mkdirs();
}
try {
// Open Connection
URL url = new URL(urlString);
// Get just the file Name from URL
String fileName = new File(url.getPath()).getName();
// Try with Resources....
try (InputStream in = url.openStream(); FileOutputStream outStream =
new FileOutputStream(new File(destinationFolderPath + fileName))) {
// Read from resource and write to file...
int length = -1;
byte[] buffer = new byte[1024]; // buffer for portion of data from connection
while ((length = in.read(buffer)) > -1) {
outStream.write(buffer, 0, length);
}
}
// File Successfully Downloaded");
result = true;
}
catch (MalformedURLException ex) { ex.printStackTrace(); }
catch (IOException ex) { ex.printStackTrace(); }
return result;
}
I am getting zipped blob from db and using that blob in below way,
Ex:-
byte[] inputBlob = blobfile.getBytes(1, (int) blobfile.length());
After getting the blob, the way i got the zippedStream and passed it into another Class method(unzipper).
Ex:-
ByteArrayOutputStream zippedStream = null;
InputStream byteInputStream = null;
IParser parser = null;
byte[] buffer = null;
try {
zippedStream = new ByteArrayOutputStream();
byteInputStream = new ByteArrayInputStream(blob);
blob = null;
int bytes_read;
buffer = new byte[byteInputStream.available()];
while ((bytes_read = byteInputStream.read(buffer)) > 0) {
zippedStream.write(buffer, 0, bytes_read);
}
buffer = null;
byteInputStream.close();
byteInputStream = null;
}catch(Exception e){
e.printStackTrace();
}
unzipper method:
Ex:-
byte[] buffer = new byte[1024];
try {
InputStream decodedInput = new ByteArrayInputStream(zippedStream.toByteArray());
zippedStream.close();
zippedStream = null;
GZIPInputStream unzippedStream = new GZIPInputStream(decodedInput);
decodedInput.close();
decodedInput = null;
int bytes_read;
unzippedOutputstream = new ByteArrayOutputStream();
while ((bytes_read = unzippedStream.read(buffer)) > 0) {
unzippedOutputstream.write(buffer, 0, bytes_read);
}
buffer = null;
unzippedStream.close();
unzippedStream = null;
} catch (Exception ex) {
logger.setException(ex);
logger.error("unzipper", generateMsg("Exception occurred"));
}
Using this way my application got stucked some time, and performance was so bad.
Is there any optimize way to get the zippedstream file and unzipping that easily?
Is all this buffering really needed. Can you IParser parse a Stream?
InputStream zippedStream = ...
IParser parser = ...
parser.parse(new GZIPInputStream(zippedStream));
This will read compressed data, uncompressing as it goes which is much more efficient.
Right now I am working on a task to convert binary data in to a zip file
I am calling a url and getting a response from server like
A#B�ArE⏾�7�ϫ���f�걺N�����Yg���o_M^�D�T�U X_���e?� hi\ � �ڂ(� �0 rm��'�ed���� �:6h�k�ڗ� ���fnp���7��)��:��N�U�viR�,) II����M��Np�M��7��
n��
!A!) )AAFAq)Q)�y
y� ��.�����?���
��֞��ͅ��Ɲ_�O�����nc��f��w��ʰ�6��3 2�ƢZZ��N0� O{� mC� ��$��,>����������
���CW/)?�?٥��ߗ�d�=�R�J*E{2L���ח�W���ӑ_PRR�_#�_H��:������Ə�Ջ�J�^v�0wo��+�o���
�-Ä#�R6��P�(���0�WPj�k�
C�E
now I want to save this data to zip file i have searched a lot and find some links but not meet the goal.
here i have done
OutputStreamWriter osw = new OutputStreamWriter(openFileOutput(
"products.zip", Context.MODE_PRIVATE));
osw.write(data);
osw.close();
please guid me if you have any idea about this.
OutputStreamWriter osw
NO!
A Writer is made to write text, not binary.
In the first place, it looks like you read text as well, which you shouldn't.
Use an InputStream to read the original content, and an OutputStream to write into the file:
final OutputStream out = /* open your file using a FileOutputStream here */;
final byte[] buf = new byte[8096]; // size as appropriate
// "in" is the InputStream from the socket
int count;
try {
while ((count = in.read(buf)) != -1)
out.write(buf, 0, count);
out.flush();
} finally {
out.close();
}
Readers are not meant to read octet streams.
Reads text from a character-input stream, buffering characters so as to provide for the efficient reading of characters, arrays, and lines.
You're looking for a BufferedInputStream.
The getContent() method on the HttpEntity returns an InputStream. Wrap this around a BufferedInputStream and write it to a file or a ByteArrayOutputStream.
byte[] buffer = new byte[5 * 1024];
int numRead = -1;
while( (numRead = bufferedInputStream.read(buffer))!= -1)
{
byteArrayOutputStream.write(buffer, 0, numRead);
}
byteArrayOutputStream.flush();
byteArrayOutputStream.close();
byte[] result = byteArrayOutputStream.toByteArray();
To save on memory I'd advise you to write to a BufferedOutputStream instead of trying to get the bytes from the stream into a data structure. The android device is likely to run out of memory for large zip files.
You might be able to avoid the trouble of converting Binary by adding options to your request.
In NodeJS I specify the responseType as arraybuffer
const res = await axios.get('/routToThat/file', {
headers: {
Accept: 'application/zip',
},
responseType: 'arraybuffer',
});
So instead of receiving the server response as a Binary string:
A#B�ArE⏾�7�ϫ���f�걺N�����Yg���o_M^�D�T�U X_���e?� hi\...
I get a Buffer:
Buffer(22781691) [80, 75, 3, …]
NOTE: In my case the response I get is already a ZIP file.
More details on this NodeJS answer.
https://stackoverflow.com/a/62460311/3645464
All I need to do is construct a BufferedInputStream from the entity. Just replace BufferedReader with a BufferedInputStream. I would recommend using ISO-8859-1 .An underlying streaming encoder to read binary data is a waste of processing power.
private class methodName extends
AsyncTask<String, Integer, byte[]> {
#Override
protected byte[] doInBackground(String... params) {
String uri = params[0];
try {
MultipartEntityBuilder entity;
File f;
FileBody fb;
entity = MultipartEntityBuilder.create();
entity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
f = new File(zipImageFile);
fb = new FileBody(f);
entity.addPart("orderFile", fb);
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(uri);
Log.e("Uploload Missing Image URL", "" + uri);
httppost.setEntity(entity.build());
HttpResponse response = httpclient.execute(httppost);
// byte[] fileBites=null;
BufferedInputStream bufferedInputStream;
ByteArrayOutputStream byteArrayOutputStream;
byte[] buffer = new byte[5 * 1024];
int numRead = -1;
while( (numRead = bufferedInputStream.read(buffer))!= -1)
{
byteArrayOutputStream.write(buffer, 0, numRead);
}
byteArrayOutputStream.flush();
byteArrayOutputStream.close();
byte[] result = byteArrayOutputStream.toByteArray();
// fileBites=stringBuffer.toString().getBytes();
// Log.e("FILE BITES", fileBites+"=>"+fileBites.length);
return ;
// return stringBuffer.toString();
} catch (Exception e) {
return e.toString().getBytes();
}
}
#Override
protected void onPostExecute(byte[] result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
Log.e("Response From Server", "" + result);
writeToFile(result);
}
}
private void writeToFile(byte[] data) {
try {
FileOutputStream fop = null;
File file;
file = new File(AppConstants.DataPath+"/products.zip");
fop = new FileOutputStream(file);
// if file doesnt exists, then create it
if (!file.exists()) {
file.createNewFile();
}
try {
fop.write(data);
} catch (IOException e) {
Log.e("Exception", "File write failed: " + e.toString());
}
unzipImage(AppConstants.DataPath + "/products.zip",
AppConstants.DataPath);
}catch (Exception E)
{
}
}
I just want to create a File object like this
File myImageFile = new File ("image1") ;
but it is giving me exception of FileNotFoundException
How can i reference a file inside my raw Folder
EDIT:
Actually i wanted to do something like this
MultipartEntity multipartEntity= new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
multipartEntity.addPart("uploaded", new FileBody(new File("myimage")));
Generally you access the files through getResources().openRawResource(R.id._your_id). If you absolutely need a File reference to it, one option is to copy it over to internal storage:
File file = new File(this.getFilesDir() + File.separator + "DefaultProperties.xml");
try {
InputStream inputStream = resources.openRawResource(R.id._your_id);
FileOutputStream fileOutputStream = new FileOutputStream(file);
byte buf[]=new byte[1024];
int len;
while((len=inputStream.read(buf))>0) {
fileOutputStream.write(buf,0,len);
}
fileOutputStream.close();
inputStream.close();
} catch (IOException e1) {}
Now you have a File that you can access anywhere you need it.
here are 2 functions. one to read from RAW and one from the Assets
/**
* Method to read in a text file placed in the res/raw directory of the
* application. The method reads in all lines of the file sequentially.
*/
public static void readRaw(Context ctx,int res_id) {
InputStream is = ctx.getResources().openRawResource(res_id);
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr, 8192); // 2nd arg is buffer
// size
// More efficient (less readable) implementation of above is the
// composite expression
/*
* BufferedReader br = new BufferedReader(new InputStreamReader(
* this.getResources().openRawResource(R.raw.textfile)), 8192);
*/
try {
String test;
while (true) {
test = br.readLine();
// readLine() returns null if no more lines in the file
if (test == null)
break;
}
isr.close();
is.close();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
and from Assets folder
/**
* Read a file from assets
*
* #return the string from assets
*/
public static String getQuestions(Context ctx,String file_name) {
AssetManager assetManager = ctx.getAssets();
ByteArrayOutputStream outputStream = null;
InputStream inputStream = null;
try {
inputStream = assetManager.open(file_name);
outputStream = new ByteArrayOutputStream();
byte buf[] = new byte[1024];
int len;
try {
while ((len = inputStream.read(buf)) != -1) {
outputStream.write(buf, 0, len);
}
outputStream.close();
inputStream.close();
} catch (IOException e) {
}
} catch (IOException e) {
}
return outputStream.toString();
}
You can open it as InputStream, I don't know if possible as a file:
int rid = resources.getIdentifier(packageName + ":raw/" + fileName, null, null);
//get the file as a stream
InputStrea is = resources.openRawResource(rid);
You can use InputStreamBody instead of FileBody so you can use it like this:
InputStream inputStream = resources.openRawResource(R.raw.yourresource);
MultipartEntity multipartEntity= new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
multipartEntity.addPart("uploaded", new InputStreamBody(inputStream));
I'm calling a script that gives me a binary file (12345.cl), with binary data. The script is done, and it's working, if I paste it on the navigator I get the binary file.
Now I have a problem: How I transform the response of the script into a binary resource to use it in my app?
For the moment, i have this code:
public void decodeStream( String mURL ){
BufferedInputStream bis = new BufferedInputStream(new URL(mURL).openStream(), BUFFER_IO_SIZE);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(baos, BUFFER_IO_SIZE);
copy(bis, bos);
bos.flush();
Then, I have a BufferedOutputStream with the response, but I don't know how to transform it into a binary resource to use it
I need to obtain a datainputstream with the file but I don't know how to achieve it
You can use following code:
public void decodeStream( String mURL, String ofile ) throws Exception {
InputStream in = null;
FileOutputStream out = null;
try {
URL url = new URL(mURL);
URLConnection urlConn = url.openConnection();
in = urlConn.getInputStream();
out = new FileOutputStream(ofile);
int c;
byte[] b = new byte[1024];
while ((c = in.read(b)) != -1)
out.write(b, 0, c);
} finally {
if (in != null)
in.close();
if (out != null)
out.close();
}
}