little bit of a pickle here. I am reading a JSON From a Zip file and I want to fill a table in Vaadin with the contents of the JSON.
Here's my Function to read the stuff and fill the table, this is Java.
private void getJsonContent() {
try {
FileInputStream fis = new FileInputStream(backupFile);
ZipInputStream zin = new ZipInputStream(new BufferedInputStream(fis));
ZipEntry entry;
byte[] buffer = new byte[1024];
while((entry = zin.getNextEntry()) != null) {
if(entry.getName().equalsIgnoreCase("content.json")) {
int n;
while((n = zin.read(buffer, 0, 1024)) > -1){
String JSON = new String(buffer, Charset.forName("UTF-8"));
JSONObject obj = new JSONObject(JSON);
logger.info(JSON);
// Assign "global" Values to Variables
this.createdAt = obj.getString("created_at");
this.version = obj.getString("version");
// Fill table if applicable
for(int i = 0; i < obj.getJSONArray("content").length(); i++) {
JSONObject sub = obj.getJSONArray("content").getJSONObject(i);
logger.info(sub);
infoTable.addItem(new Object[] {
sub.get("imported_identities").toString(),
sub.get("project_versions").toString(),
sub.get("last_import").toString(),
sub.get("client").toString(),
sub.get("project").toString()
}, i +1);
}
}
}
}
zin.close();
fis.close();
} catch (FileNotFoundException e) {
// Can't happen here
} catch (IOException e) {
logger.info("Can't read File.");
} catch (JSONException jse) {
logger.info("JSON Content could not be read: " + jse.getMessage());
}
}
You will notice I have a function call logger.info(sub) - to make sure what I get is another valid JSON Object (the file I am reading contains nested things)
Output:
{"imported_identities":0,"project_versions":0,"last_import":null,"client":"Client1","project":"Project2"}
{"imported_identities":0,"project_versions":0,"last_import":null,"client":"Client2","project":"Project1"}
{"imported_identities":0,"project_versions":1,"last_import":"2016-09-14T09:28:24.520Z","client":"Client1","project":"Project1"}
I made sure all the values were correct (and the table is built with null as default) - here is the table properties:
infoTable.addContainerProperty(impIds, String.class, null);
infoTable.addContainerProperty(projVe, String.class, null);
infoTable.addContainerProperty(lstImp, String.class, null);
infoTable.addContainerProperty(client, String.class, null);
infoTable.addContainerProperty(projct, String.class, null);
infoTable.setColumnCollapsingAllowed(true);
infoTable.setColumnCollapsed(impIds, true);
infoTable.setColumnCollapsed(projVe, true);
infoTable.setColumnCollapsed(lstImp, true);
Finally, the table has "refreshRowCache" called on it. Anyone see the problem? There are no errors, no nothing, the table just doesn't add the item (the size of infoTable.getItemIds().size() is 0 right after the call.
EDIT:
I tried the following to verify.
infoTable.addItem(i + 1);
infoTable.getItem(i + 1).getItemProperty(impIds).setValue(sub.get("imported_identities").toString());
infoTable.getItem(i + 1).getItemProperty(projVe).setValue(sub.get("project_versions").toString());
This went and caused a NullPointerException, the stack trace however does not contain any of my classes as far as I can see.
The following is wrong:
The String constructor needs the read size (n).
while ((n = zin.read(buffer, 0, 1024)) > -1) {
String JSON = new String(buffer, 0, n, StandardCharsets.UTF_8);
Then you do JSONs of at most 1024 in the loop, instead on one JSON of it all
The bytes of a UTF-8 cannot be split at some point say at position 1024 and expect to have a valid complete multi-byte sequence at end and following block's begin.
Also there is readFully and closeEntry was missing.
In short:
private void getJsonContent() {
try (ZipInputStream zin = new ZipInputStream(new BufferedInputStream(
new FileInputStream(backupFile)))) {
ZipEntry entry;
while ((entry = zin.getNextEntry()) != null) {
if (entry.getName().equalsIgnoreCase("content.json")) {
long size = entry.getSize();
if (size > 100_000) {
throw new IllegalArgumentException("Data too large");
}
// We could use an InputStreamReader and read text piecewise.
// However JSON parsing also is easiest on an entire text.
byte[] buffer = new byte[(int)size];
int n = zin.readFully(buffer, 0, buffer.length);
String json = new String(buffer, StandardCharsets.UTF_8);
JSONObject obj = new JSONObject(json);
logger.info(json);
// Assign "global" Values to Variables
this.createdAt = obj.getString("created_at");
this.version = obj.getString("version");
// Fill table if applicable
for (int i = 0; i < obj.getJSONArray("content").length(); i++) {
JSONObject sub = obj.getJSONArray("content").getJSONObject(i);
logger.info(sub);
infoTable.addItem(new Object[] {
sub.get("imported_identities").toString(),
sub.get("project_versions").toString(),
sub.get("last_import").toString(),
sub.get("client").toString(),
sub.get("project").toString()
}, i + 1);
}
} // if
zin.closeEntry(); // Do not forget preparing for the next entry
}
} catch (IOException e) {
logger.info("Can't read File.");
} catch (JSONException jse) {
logger.info("JSON Content could not be read: " + jse.getMessage());
}
}
The try-with-resources closes automatically even on exception or return.
Related
As per my requirement I want to create checksum value using SHA-256, from InputStream,
As below:
private InputStream createZipInput(List<ResponsePack> aList, byte[] manifestData)
{
final int bufferSize = 2048;
byte buffer[] = new byte[bufferSize];
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
ZipOutputStream zipFileToSend = new ZipOutputStream(byteStream);
LOG.trace("Compressing the file {}");
try
{
for (ResponsePack info : aList)
{
ByteArrayOutputStream byteStreamCheckSum = new ByteArrayOutputStream();
ZipOutputStream zipFileToSendCheckSum = new ZipOutputStream(byteStreamCheckSum);
zipFileToSend.putNextEntry(new ZipEntry(info.getFileName()));
zipFileToSendCheckSum.putNextEntry(new ZipEntry(info.getFileName()));
InputStream in = info.getFileContentStream();
int length;
while ((length = in.read(buffer)) >= 0)
{
zipFileToSend.write(buffer, 0, length);
zipFileToSendCheckSum.write(buffer, 0, length);
}
zipFileToSend.closeEntry();
zipFileToSendCheckSum.closeEntry();
String checksum = validChecksum(byteStreamCheckSum.toByteArray());
LOG.error("Checksum {}", checksum);
zipFileToSendCheckSum.flush();
zipFileToSendCheckSum.close();
}
zipFileToSend.close();
}
catch (IOException e)
{
return e;
}
return new ByteArrayInputStream(byteStream.toByteArray());
}
private static String validChecksum(byte[] dataCopy)
{
printLOG("Byte Array Size {}", dataCopy.length);
try (ZipInputStream zipInputStream = new ZipInputStream(new ByteArrayInputStream(dataCopy)))
{
ZipEntry zipEntry;
MessageDigest digest = DigestUtils.getSha256Digest();
DWriter writer = new DWriter(digest);
while ((zipEntry = zipInputStream.getNextEntry()) != null)
{
org.apache.commons.io.output.ByteArrayOutputStream dest = StreamUtils.extractFileAsByteArrayStream(zipInputStream);
LOG.error("CheckSum Entity creating");
if(zipEntry != null)
{
printLOG("CheckSum Entity file Name {}", zipEntry.getName());
}
LOG.error("Byte array size {}", dest.toByteArray().length);
writer.write(dest.toByteArray());
dest.flush();
dest.close();
}
if (writer.getChecksum() != null)
{
return writer.getChecksum();
}
else
{
return "";
}
}
catch (Exception e)
{
printLOG("Exception encountered while creating checksum: {}", e.getMessage());
return "";
}
}
static class DWriter
{
private final MessageDigest myDigest;
DWriter(MessageDigest digest)
{
myDigest = digest;
}
public void write(byte[] data)
{
myDigest.update(data);
}
public String getChecksum()
{
return new String(Hex.encodeHex(myDigest.digest()));
}
}
But the problem is when I checked the log, found byte array contains value but still checksum always creating for empty string, as below
Byte Array Size 3948
CheckSum Entity creating
CheckSum Entity file Name 20200911104812526.json
Byte array size 20854
Checksum e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Help me where I am doing wrong, due to which I am getting checksum for an empty string
I'm not sure what's wrong with the code but it seems overly complicated: you're writing the input into a zipped stream and the dezip it in memory to read it again.
You don't need to do that: storing the input in a (non-zipped) byte array should be enough.
I think you need to make sure that in.read() works as intended (and that there's actually some data to read).
You get the checksum for a null input and your zip entry is also empty, so it looks like the input was empty. Add some logs or use a debugger to investigate what's happening.
private InputStream createZipInput(List<ResponsePack> aList, byte[] manifestData) {
final int bufferSize = 2048;
byte buffer[] = new byte[bufferSize];
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
ZipOutputStream zipFileToSend = new ZipOutputStream(byteStream);
LOG.trace("Compressing the file {}");
try {
for (ResponsePack info : aList) {
ByteArrayOutputStream byteStreamCheckSum = new ByteArrayOutputStream();
zipFileToSend.putNextEntry(new ZipEntry(info.getFileName()));
InputStream in = info.getFileContentStream();
int length;
while ((length = in.read(buffer)) != -1) {
zipFileToSend.write(buffer, 0, length);
byteStreamCheckSum.write(buffer, 0, length);
}
zipFileToSend.closeEntry();
MessageDigest digest = DigestUtils.getSha256Digest();
digest.update(byteStreamCheckSum.toByteArray());
String checksum = new String(Hex.encodeHex(digest.digest()));
LOG.error("Checksum {}", checksum);
}
zipFileToSend.close();
} catch (IOException e) {
throw e;
}
return new ByteArrayInputStream(byteStream.toByteArray());
Below is my code. I am converting images into bytearray values.
Here finalPathNames.size() == 4
So i want to save the byteArray values eachtime like byteArray1,byteArray2,byteArray3,byteArray4 which is inside for loop
Set<String> finalPathNames = sharedpre.getStringSet("prePathNames", null);
InputStream is = null;
for (String temp : finalPathNames) {
try {
is = new FileInputStream(temp);
try {
byteArray = streamToBytes(is);
} finally {
is.close();
}
} catch (Exception e) {
}
}
is there any optimized way to find result values
Send the bytes to the server, when you retrieve them or keep them in a list (in case you need them more than 1 time)
// as mentioned in the comments, user wants specifically 4 arrays
byte[][] byteArrays = byte[4][]; //
Set<String> finalPathNames = sharedpre.getStringSet("prePathNames", null);
InputStream is = null;
int index = 0;
for (String temp : finalPathNames) {
byteArrays[index] = new byte[0]; // in case of exception clear array. possibly set to null
try {
is = new FileInputStream(temp);
try {
byte[] byteArray = streamToBytes(is);
byteArrays[index] = byteArray;
} finally {
is.close();
}
} catch (Exception e) {
}
finally {
index++;
}
}
Then the resulting streams are available as:
byteArrays[0], byteArrays[1], byteArrays[2], byteArrays[3],
I am making this J2ME application but I am having some problem when I am trying to save I thinks that it save properly but I am not sure....but when I retrieve it gives null
This is how I am storing them
PAR par = new PAR(oldMonPay, newMonPay, oldInterest);
par.setOldMPay(oldMonPay);
par.setNewMPay(newMonPay);
par.setOldInt(oldInterest);
And this is how I saving and retrieving
public static byte[] parseObjPAR(PAR p) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream out;
try {
out = new DataOutputStream(baos);
out.writeUTF(p.getNewMPay());
out.writeUTF(p.getOldInt());
out.writeUTF(p.getOldMPay());
} catch (IOException e) {
}
return baos.toByteArray();
}
public static PAR parseByteArrPAR(byte[] b) {
PAR p = null;
ByteArrayInputStream bais;
DataInputStream in;
if (b != null) {
try {
bais = new ByteArrayInputStream(b);
in = new DataInputStream(bais);
p = new PAR(
in.readUTF(),
in.readUTF(),
in.readUTF());
} catch (IOException e) {
}
}
return p;
}
This is how I displaying the retrieved information, there is another problem this thing is not showing all the data but is only showing the 3 records. I think the first 3.
public void populatePAResult(PAR[] p) {
try {
for (int i = 0; i < p.length; i++) {
String oldMP = p[i].getOldMPay();
String newMP = p[i].getNewMPay();
String oldI = p[i].getOldInt();
result1.append("Day : " + oldMP, null);
result1.append("Time : " + oldI, null);
result1.append("Technology : " + newMP, null);
}
} catch (Exception e) {
}
}
In the parseObjPAR method that writes the data the order is:
out.writeUTF(p.getNewMPay());
out.writeUTF(p.getOldInt());
out.writeUTF(p.getOldMPay());
whereas when you read it back in and pass the order the constructor is expecting is different:
PAR par = new PAR(oldMonPay, newMonPay, oldInterest);
so even if it wasn't null the loaded data would be invalid.
Hi i am using an HttpURLConnection that gets a txt file's content and i want to know the size of that file and i use the content length Method but it returns wrong value for example in this code the file's size is 17509 but it returns 5147 ?
so Any Help?
Thanks so much in advance :).
new Thread() {
#Override
public void run() {
String path = parser.getValue(e, "txt");
URL u = null;
try {
u = new URL(path);
HttpURLConnection c = (HttpURLConnection) u
.openConnection();
c.setRequestMethod("GET");
c.connect();
int lenghtOfFile = c.getContentLength();
InputStream in = c.getInputStream();
final ByteArrayOutputStream bo = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
long total = 0;
Log.i("p1",""+lenghtOfFile);
while ((count = in.read(buffer)) != -1) {
total += count;
Log.i("p2",""+total);
bo.write(buffer, 0, count);
}
bo.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
The content-length is a header set by the server. I would check to make sure that your server is returning the correct content-length. You can do that with cUrl:
curl -v http://path/to/file.txt
That should show you the headers that were sent and returned.
A quick workaround I can think of, is just ignoring the content-length and reading input stream until there's nothing left to read.
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(8192);
int read = inputStream.read();
while (read != -1) {
byteArrayOutputStream.write((byte) read);
read = inputStream.read();
}
byteArrayOutputStream.flush();
buf = byteArrayOutputStream.toByteArray();
I am trying to get file content in bytes in Android application. I have get the file in SD card now want to get the selected file in bytes. I googled but no such success. Please help
Below is the code to get files with extension. Through this i get files and show in spinner. On file selection I want to get file in bytes.
private List<String> getListOfFiles(String path) {
File files = new File(path);
FileFilter filter = new FileFilter() {
private final List<String> exts = Arrays.asList("jpeg", "jpg", "png", "bmp", "gif","mp3");
public boolean accept(File pathname) {
String ext;
String path = pathname.getPath();
ext = path.substring(path.lastIndexOf(".") + 1);
return exts.contains(ext);
}
};
final File [] filesFound = files.listFiles(filter);
List<String> list = new ArrayList<String>();
if (filesFound != null && filesFound.length > 0) {
for (File file : filesFound) {
list.add(file.getName());
}
}
return list;
}
here it's a simple:
File file = new File(path);
int size = (int) file.length();
byte[] bytes = new byte[size];
try {
BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
buf.read(bytes, 0, bytes.length);
buf.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Add permission in manifest.xml:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
The easiest solution today is to used Apache common io :
http://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/FileUtils.html#readFileToByteArray(java.io.File)
byte bytes[] = FileUtils.readFileToByteArray(photoFile)
The only drawback is to add this dependency in your build.gradle app :
implementation 'commons-io:commons-io:2.5'
+ 1562 Methods count
Since the accepted BufferedInputStream#read isn't guaranteed to read everything, rather than keeping track of the buffer sizes myself, I used this approach:
byte bytes[] = new byte[(int) file.length()];
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
DataInputStream dis = new DataInputStream(bis);
dis.readFully(bytes);
Blocks until a full read is complete, and doesn't require extra imports.
Here is a solution that guarantees entire file will be read, that requires no libraries and is efficient:
byte[] fullyReadFileToBytes(File f) throws IOException {
int size = (int) f.length();
byte bytes[] = new byte[size];
byte tmpBuff[] = new byte[size];
FileInputStream fis= new FileInputStream(f);;
try {
int read = fis.read(bytes, 0, size);
if (read < size) {
int remain = size - read;
while (remain > 0) {
read = fis.read(tmpBuff, 0, remain);
System.arraycopy(tmpBuff, 0, bytes, size - remain, read);
remain -= read;
}
}
} catch (IOException e){
throw e;
} finally {
fis.close();
}
return bytes;
}
NOTE: it assumes file size is less than MAX_INT bytes, you can add handling for that if you want.
If you want to use a the openFileInput method from a Context for this, you can use the following code.
This will create a BufferArrayOutputStream and append each byte as it's read from the file to it.
/**
* <p>
* Creates a InputStream for a file using the specified Context
* and returns the Bytes read from the file.
* </p>
*
* #param context The context to use.
* #param file The file to read from.
* #return The array of bytes read from the file, or null if no file was found.
*/
public static byte[] read(Context context, String file) throws IOException {
byte[] ret = null;
if (context != null) {
try {
InputStream inputStream = context.openFileInput(file);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
int nextByte = inputStream.read();
while (nextByte != -1) {
outputStream.write(nextByte);
nextByte = inputStream.read();
}
ret = outputStream.toByteArray();
} catch (FileNotFoundException ignored) { }
}
return ret;
}
In Kotlin you can simply use:
File(path).readBytes()
You can also do it this way:
byte[] getBytes (File file)
{
FileInputStream input = null;
if (file.exists()) try
{
input = new FileInputStream (file);
int len = (int) file.length();
byte[] data = new byte[len];
int count, total = 0;
while ((count = input.read (data, total, len - total)) > 0) total += count;
return data;
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
if (input != null) try
{
input.close();
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
return null;
}
A simple InputStream will do
byte[] fileToBytes(File file){
byte[] bytes = new byte[0];
try(FileInputStream inputStream = new FileInputStream(file)) {
bytes = new byte[inputStream.available()];
//noinspection ResultOfMethodCallIgnored
inputStream.read(bytes);
} catch (IOException e) {
e.printStackTrace();
}
return bytes;
}
Following is the working solution to read the entire file in chunks and its efficient solution to read the large files using a scanner class.
try {
FileInputStream fiStream = new FileInputStream(inputFile_name);
Scanner sc = null;
try {
sc = new Scanner(fiStream);
while (sc.hasNextLine()) {
String line = sc.nextLine();
byte[] buf = line.getBytes();
}
} finally {
if (fiStream != null) {
fiStream.close();
}
if (sc != null) {
sc.close();
}
}
}catch (Exception e){
Log.e(TAG, "Exception: " + e.toString());
}
To read a file in bytes, often used to read binary files, such as pictures, sounds, images, etc.
Use the method below.
public static byte[] readFileByBytes(File file) {
byte[] tempBuf = new byte[100];
int byteRead;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file));
while ((byteRead = bufferedInputStream.read(tempBuf)) != -1) {
byteArrayOutputStream.write(tempBuf, 0, byteRead);
}
bufferedInputStream.close();
return byteArrayOutputStream.toByteArray();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}