I am trying to send a encoded string to Solr and then decode it on retrieval. My encode looks like:
public static String compress(String inputString) {
try {
if (inputString == null || inputString.length() == 0) {
return null;
}
return new String(compress(inputString.getBytes("UTF-8")));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
private static byte[] compress(byte[] input) {
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(out);
gzip.write(input);
gzip.close();
return out.toByteArray();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
Then I send the to SOLR, and when I try to get it back (ignoring decoding for now because it fails here)
SolrDocument resultDoc = iter.next();
String content = (String) resultDoc.getFieldValue("source");
System.out.println(content);
If I send a string such as "Hello my name is Chris" the encoded will look like (ignoring what stack overflow changed);
ã�������ÛHÕ……W»≠T»KÃMU»,VpŒ( ,�ìùùG���
Yet what I get back from SOLR is
#31;ã#8;#0;#0;#0;#0;#0;#0;#0;ÛHÕ……W»≠T»KÃMU»,VpŒ( ,#6;#0;ìùùG#22;#0;#0;#0;
which will obviously make decoding fail. I have tried using the Jetty install and Tomcat both with the same issue.
See this entry from the example schema.xml file that comes with the Solr distribution.
<!--Binary data type. The data should be sent/retrieved in as Base64 encoded Strings -->
<fieldtype name="binary" class="solr.BinaryField"/>
Make sure that the field you are using to store your encoded value in the index is using the binary fieldType and that you are using base64 encoded strings.
Related
I have the following task to obtain a PDF from URL and return a BASE64 string.
What I have currently (sorry I am not a Java Expert):
public String readPDFSOAP(String var, Container container) throws StreamTransformationException{
try {
//get the url page from the arguments array
URL url = new URL("URLPDF");
try {
//get input Stream from URL
InputStream in = new BufferedInputStream(url.openStream());
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[131072];
int n = 0;
while (-1 != (n = in.read(buf))) {
out.write(buf, 0, n);
}
out.close();
in.close();
byte[] response = out.toByteArray();
String string = new String(response);
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}return String;}
But the string can't be returned.
Any help is appreciated.
Thanks,
Julian
Your code is all kinds of wrong. For starters, use the Base64 class to handle encoding your byte array. And no need to assign it to a variable, just return it.
return Base64.getEncoder().encodeToString(response)
and on your last line, outside of your try/catch block, just throw an exception. If you get there then you weren't able to properly retrieve and encoded the response, so no need to return a value. You're in an error condition.
Use java.util.Base64.
PDFs can be pretty large. Instead of reading it into memory, encode the InputStream directly:
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (InputStream in = new BufferedInputStream(url.openStream())) {
in.transferTo(Base64.getEncoder().wrap(out));
}
String base64 = out.toString(StandardCharsets.US_ASCII);
The Base64 encoded version is even larger than the original file. I don’t know what you plan to do with the encoded version, but if you’re planning to write it somewhere, you want to avoid keeping any version of the file—original or encoded—in memory. You can do that by having your method accept an OutputStream as an argument:
public void readPDFSOAP(OutputStream destination,
String var,
Container container)
throws StreamTransformationException,
IOException {
URL url = new URL("https://example.com/doc.pdf");
try (InputStream in = new BufferedInputStream(url.openStream())) {
in.transferTo(Base64.getEncoder().wrap(destination));
}
}
Update:
Since you have said you cannot use a try-with-resources statement:
A try-with-resources statement is just a convenient way to guarantee an InputStream (or other closeable resource) is closed. This:
try (InputStream in = new BufferedInputStream(url.openStream())) {
// code that uses 'in'
}
is (nearly) equivalent to this:
InputStream in = null;
try {
in = new BufferedInputStream(url.openStream());
// code that uses 'in'
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
// Suppress
}
}
}
when I use apache common-codec md5Hex to get the inputstream's md5 result,but get the different result for twice. the example code is below :
public static void main(String[] args) {
String data = "D:\\test.jpg";
File file = new File(data);
InputStream is = null;
try {
is = new FileInputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
String digest = null, digest2 = null;
try {
System.out.println(is.hashCode());
digest = DigestUtils.md5Hex(is);
System.out.println(is.hashCode());
digest2 = DigestUtils.md5Hex(is);
System.out.println(is.hashCode());
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Digest = " + digest);
System.out.println("Digest2 = " + digest2);
}
and the result is:
1888654590
1888654590
1888654590
Digest = 5cc6c20f0b3aa9b44fe952da20cc928e
Digest2 = d41d8cd98f00b204e9800998ecf8427e
Thank you for answer!
d41d8cd98f00b204e9800998ecf8427e is the md5 hash of the empty string ("").
That is because is is a stream, meaning that once you've read it (in DigestUtils.md5Hex(is)), the "cursor" is at the end of the stream, where there is no more data to read, so attempting to read anything will return 0 bytes.
I suggest reading the contents of the stream to a byte[] instead, and hashing that.
For how to get a byte[] from an InputStream, see this question.
The InputStream can be traversed only once. The first call traverses it and returns the MD5 for your input file. When you call md5hex the second time, the InputStream points to the end-of-file, thus the digest2 is the MD5 for empty input.
You cannot move back within InputStream. So invoking twice:
DigestUtils.md5Hex(is);
is not the same. Better read into byte array and use:
public static String md5Hex(byte[] data)
I have these Base64 in a text file:
77u/PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxSb290Pg0KICA8SXRl
bXM+DQogICAgPEl0ZW0gTmFtZT0iQ2xhaW1OdW1iZXIiIFZhbHVlPSI0ODY1MTQ4MDQiIC8+DQog
ICAgPEl0ZW0gTmFtZT0iRG9jVHlwZSIgVmFsdWU9IkxpdGlnYXRpb24iIC8+DQogICAgPEl0ZW0g
TmFtZT0iRG9jU3ViVHlwZSIgVmFsdWU9IklOVCBBbnN3ZXJzIiAvPg0KICAgIDxJdGVtIE5hbWU9
IkRvY0RhdGVzIiBWYWx1ZT0iNi8xNC8yMDExIDEyOjAwOjAwIEFNIiAvPg0KICAgIDxJdGVtIE5h
bWU9IkNvbW1lbnRzIiBWYWx1ZT0iUGx0ZiBhbnN3ZXJzIHRvIGludHMgYW5kIHN1bW1hcnkgYnkg
ZGVmZW5zZSBjb3Vuc2VsIiAvPg0KICAgIDxJdGVtIE5hbWU9IlNlY3VyaXR5R3JvdXAiIFZhbHVl
PSJTcGVjIEdlbiIgLz4NCiAgICA8SXRlbSBOYW1lPSJDbGFpbU9mZmljZSIgVmFsdWU9IkFsdCBN
a3RzIE5KIiAvPg0KICAgIDxJdGVtIE5hbWU9IkNsYWltYW50TmFtZSIgVmFsdWU9IkpvYW4gS2Vs
bGV5IiAvPg0KICAgIDxJdGVtIE5hbWU9Ikluc3VyZWROYW1lIiBWYWx1ZT0iQm96dXR0byAmYW1w
OyBBc3NvY2lhdGVzIiAvPg0KICAgIDxJdGVtIE5hbWU9IlByaXZpbGVnZWQiIFZhbHVlPSJObyIg
Lz4NCiAgICA8SXRlbSBOYW1lPSJEaXNwb3NpdGlvbiIgVmFsdWU9IlNlbnQgdG8gRmlsZSIgLz4N
CiAgICA8SXRlbSBOYW1lPSJGZWF0dXJlIiBWYWx1ZT0iIiAvPg0KICAgIDxJdGVtIE5hbWU9IlNl
bnRUbyIgVmFsdWU9IiIgLz4NCiAgICA8SXRlbSBOYW1lPSJGbGFnIiBWYWx1ZT0iMCIgLz4NCiAg
ICA8SXRlbSBOYW1lPSJSZXRhaW5JbWFnZSIgVmFsdWU9Ik5vIiAvPg0KICAgIDxJdGVtIE5hbWU9
IlJldGFpbk9yaWdpbmFsIiBWYWx1ZT0iRG8gTm90IFJldGFpbiIgLz4NCiAgICA8SXRlbSBOYW1l
PSJTb3VyY2UiIFZhbHVlPSJJTkRFWEVEIiAvPg0KICA8L0l0ZW1zPg0KICA8Um91dGU+DQogICAg
PHRvIC8+DQogICAgPGNjIC8+DQogICAgPE5vdGUgLz4NCiAgPC9Sb3V0ZT4NCjwvUm9vdD4=
I need to be able to take those base 64 charecters from the text file and output a new XML File. Currently, the InputStream is not being correctly converted to base 64
public static void main(String[] args) {
try {
File file = new File("C:\\Users\\khurt\\Desktop\\xml.txt");
InputStream myScan = new FileInputStream(file);
byte[] b = new byte[(int)file.length()];
myScan.read(b);
String cowo = myScan.toString();
String decoded = DatatypeConverter.printBase64Binary(b);
String cat = b.toString();
System.out.println(decoded);
byte[] bArray = cat.getBytes();
OutputStream out = new FileOutputStream("C:\\Users\\gdfurt\\Desktop\\cow.xml");
out.write(b);
out.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
I used the System.out.println(decode); to check to see if the charecters matched the ones in the file and they do not. I can't figure out why, I have tried using a scanner and that throws it off more.
Data you have got is Base64 encoded. and you are not decoding it in your code. That is main reason behind other programs cannot read it as XML file.
Another is hidden in your Bytes of data. Start of Byte data is 77u/ which is saying data is BINARY data and becomes problem here.
Use Link to experience decoded data:
http://www.opinionatedgeek.com/dotnet/tools/base64decode/
If you will use 77u/ at start of data you will experience data is BINARY and will get downloaded as file. And if you do not use 77u/ it will show output online only.
Remove first 4 char while processing your data and then you are good to go inside java code only.
EDIT
Please use below code snippet. You are re-encoding byte array. You need to decode it. Also this process needs little bit conversions of String to Byte and vice-versa.
try {
File file = new File("C:\\Users\\ABC\\Desktop\\xml.txt");
InputStream myScan = new FileInputStream(file);
byte[] b = new byte[(int)file.length()];
myScan.read(b);
String cowo = new String(b);
System.out.println( cowo );
String decoded = new String(DatatypeConverter.parseBase64Binary(cowo));
String cat = b.toString();
System.out.println(decoded);
byte[] bArray = cat.getBytes();
OutputStream out = new FileOutputStream("C:\\Users\\ABC\\Desktop\\cow.xml");
out.write(decoded.getBytes());
out.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Read the bytes:
byte[] b;
try (InputStream in = new FileInputStream(file)) {
b = new byte[(int) file.length()];
in.read(b);
} // Closes in
Which in Java 7 goes easier:
b = Files.readAllBytes(file.toPath());
or immediately with Path i.o. Fiile:
Path path = Paths.get("C:\\Users\\khurt\\Desktop\\xml.txt");
b = Files.readAllBytes(path);
As Base64 only uses ASCII do:
String encoded = new String(b, StandardCharsets.US_ASCII);
Parse Base64 text to byte[]
b = DatatypeConverter.parseBase64Binary(encoded);
If you want the XML as text:
String decoded = new String(b, StandardCharsets.UTF_8);
By the way, the XML starts with "\ufeff" the Unicode BOM character, which is redundand.
Addendum 2021-11-16
Nowadays there is one Base64 class in java SE:
b = Base64.getDecoder().decode(b);
or even (suitable for large files):
b = Base64.getDecoder().decode(Files.newInputStream(path));
Hi I would like to know if there is any way in Java to reduce the size of an image.Actually My front end is IOS,they are sending Base 64 encode data and when i'm getting the encoded data and i'm decoding the encoded data and storing in byte array. and now i want to compress the PNG image in java and my method code something like
public String processFile(String strImageBase64, String strImageName,String donorId)
{
FileOutputStream fos =null;
File savedFile=null;
try
{
String FileItemRefPath = propsFPCConfig.getProperty("fileCreationReferencePath");
String imageURLReferncePath = propsFPCConfig.getProperty("imageURLReferncePath");
File f = new File(FileItemRefPath+"\\"+"productimages"+"\\"+donorId);
String strException = "Actual File "+f.getName();
if(!f.exists())
{
boolean isdirCreationStatus = f.mkdir();
}
String strDateTobeAppended = new SimpleDateFormat("yyyyMMddhhmm").format(new Date(0));
String fileName = strImageName+strDateTobeAppended;
savedFile = new File(f.getAbsolutePath()+"\\"+fileName);
strException=strException+" savedFile "+savedFile.getName();
Base64 decoder = new Base64();
byte[] decodedBytes = decoder.decode(strImageBase64);
if( (decodedBytes != null) && (decodedBytes.length != 0) )
{
System.out.println("Decoded bytes length:"+decodedBytes.length);
fos = new FileOutputStream(savedFile);
System.out.println(new String(decodedBytes) + "\n") ;
int x=0;
{
fos.write(decodedBytes, 0, decodedBytes.length);
}
fos.flush();
}
//System.out.println(savedFile.getCanonicalPath() +" savedFile.getCanonicalPath() ");
if(fos != null)
{
fos.close();
return savedFile.getAbsolutePath();
}
else
{
return null;
}
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
try
{
if( fos!= null)
{
fos.close();
}
else
{
savedFile = null;
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
return savedFile.getName();
}
and i'm storing this decoded data with imagename,now i want to store this compressed image in anothe url
I don't think this should be worth the effort.
PNGs already have a very high level of compression. It is hard to reduce the size by means of additional compression significantly.
If you are really sending the image or the response Base64 encoded to the client, of course there are ways to improve transfer rates: Enable gzip compression on your server so that HTTP responses will be gzip compressed. This reduces the actual number of bytes to transfer quite a bit in case the original data is Base64 encoded (which basically means that you are only using 6 of 8 bits per bytes). Enabling gzip compression is transparent to your server code and is just a configuration switch away for most webservers.
i have question about sending and getting the encoded data for image. Firstly i have image as Base64 encoded type in String, this string has a value such as below :
...D/2wBDAA0JCgsKCA0LCgsODg0PEyAVExISEyccHhcgLikxMC4pLSwzOko+MzZ...
Now if i decode again and if i use BitmapFactory to accomodate on imageview thats all right the image is ok.
byte[] bytes= stream.toByteArray();
imagestr=Base64.encodeBytes(bytes).toString();
//If i code below it is working
byte[] decode = Base64.decode(imagestr);
decoded = BitmapFactory.decodeByteArray(decode, 0, decode.length);
//If i send to the server and handle it in servlet file
String pic = request.getParameter("p");
byte[] servdec = Base64.decode(pic);
//and if i use the servdec to output a image file file is corrupted.
//I noticed the pic and imagestr are different
//imagestr = **...D/2wBDAA0JCgsKCA0LCgsODg0PEyAVExISEyccHhcgLikxMC4pLSwzOko+MzZ...**
//pic = **...D/2wBDAA0JCgsKCA0LCgsODg0PEyAVExISEyccHhcgLikxMC4pLSwzOko MzZ...**
//pic has no + sign.
I used replaceAll but it is only for this case. It may cause more prob. so is there any solution can you advice thank you for your answers...
Hi, this string is in pic which comes to this function, after this function servlet will handle this !pic has + sign in this function
public String uuidfaceid(String uuid,String faceid, String name,String pic){
URL url = null;
try {
url = new
URL("http://"+Constants.SERVER_NAME+Constants.SERVER_PORT+"/MeetInTouch/UF"+"?
uuid="+uuid+"&faceid="+faceid+"&name="+name+"&pic="+pic);
} catch (MalformedURLException e1) {
e1.printStackTrace();
}
URLConnection ucon = null;
try {
ucon = url.openConnection();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
ucon.connect();
} catch (IOException e1) {
e1.printStackTrace();
}
The parameter that "p" that contains the Base64 encoded string has been "url decoded" at some point. All you have to do is encode it again before you try to decode the Base64:
String pic = request.getParameter("p");
pic = URLEncoder.encode(pic, "ISO-8859-1");
byte[] servdec = Base64.decode(pic);