md5 check on inputstream without saving as file - java

I am developing a page to upload files. I am using spring framework 3 multipartFile. I only want to save this uploaded file if it has been changed form its original version in the server. Is there a way I can do MD5 check without saving this uploaded file in a temporary location?
Thanks,
Vasanta

You can use MultipartFile's getBytes() method to read the contents as byte array, and then:
byte[] uploadBytes = upload.getBytes();
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] digest = md5.digest(uploadBytes);
String hashString = new BigInteger(1, digest).toString(16);
System.out.println("File hash: " + hashString);
However, according to the documentation the file can potentially still be saved to a temporary folder (but Spring would clean it up afterwards):
The file contents are either stored in memory or temporarily on disk.

Related

Read and Append data to the File from a Blob URL path before download

This is my first hands on using Java Spring boot in a project, as I have mostly used C# and I have a requirement of reading a file from a blob URL path and appending some string data(like a key) to the same file in the stream before my API downloads the file.
Here are the ways that I have tried to do it:
FileOutputStream/InputStream: This throws a FileNotfoundException as it is not able to resolve the blob path.
URLConnection: This got me somewhere and I was able to download the file successfully but when I tried to write/append some value to the file before I download, I failed.
the code I have been doing.
//EXTERNAL_FILE_PATH is the azure storage path ending with for e.g. *.txt
URL urlPath = new URL(EXTERNAL_FILE_PATH);
URLConnection connection = urlPath.openConnection();
connection.setDoOutput(true); //I am doing this as I need to append some data and the docs mention to set this flag to true.
OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
out.write("I have added this");
out.close();
//this is where the issues exists as the error throws saying it cannot read data as the output is set to true and it can only write and no read operation is allowed. So, I get a 405, Method not allowed...
inputStream = connection.getInputStream();
I am not sure if the framework allows me to modify some file in the URL path and read it simultaneously and download the same.
Please help me in understanding if they is a better way possible here.
From logical point of view you are not appending data to the file from URL. You need to create new file, write some data and after that append content from file from URL. Algorithm could look like below:
Create new File on the disk, maybe in TMP folder.
Write some data to the file.
Download file from the URL and append it to file on the disk.
Some good articles from which you can start:
Download a File From an URL in Java
How to download and save a file from Internet using Java?
How to append text to an existing file in Java
How to write data with FileOutputStream without losing old data?

How to write a correct zipfile checksum value, and make it as part of zipfile content

Currently, my app will perform zip process on list of files on disk, and allow user to send as email attachment for backup purpose.
To have data corruption detection capability, I generate checksum by using the following method
public static long getChecksum(File file) {
FileInputStream stream = null;
CheckedInputStream cis = null;
try {
// Compute Adler-32 checksum
stream = new FileInputStream(file);
cis = new CheckedInputStream(stream, new Adler32());
byte[] tempBuf = new byte[128];
while (cis.read(tempBuf) >= 0) {
}
long checksum = cis.getChecksum().getValue();
return checksum;
} catch (IOException ex) {
Log.e(TAG, "", ex);
} finally {
org.yccheok.gui.Utils.close(cis);
org.yccheok.gui.Utils.close(stream);
}
return 0;
}
I tend to embed the checksum info as filename
myapp_12-dec-15_3659593860.zip
To me, the filename is not really human friendly,
I wish I can have the filename like
myapp_12-dec-15.zip
If I want to achieve so, I need to write the checksum in a text file, and make it as part of zip file content.
However, this creates a paradox.
If I write the checksum file into the zip file, the previous computed checksum will no longer be valid.
If I want to compute the checksum only after writting checksum file into zip file, what should be the content of checksum file?
Since your making your own checksum computation and validation algorithm, I think you can make the following assumption: zip files contain data and metadata. Data is the files the user has selected from his disk. Metadata is the file with the checksum of the data, also available in the zip.
Then the checksum is not computed from the complete zip file, but from the user's data only, then adding it to a zip file does not change the checksum.
Zip format supports checsums by itself. ZipEntry class (if you use it) has CRC-related functionality:
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(file));
String fileInZip = "mytext.txt";
ZipEntry e = new ZipEntry(fileInZip);
e.setCrc(calcCRC(fileInZip));
That will add crc checksums to each file in archive.
Another option will be add 32-bytes-long crc checksum (for example) to the end of zip file. On file check you should read last 32 bytes of archive for checksum, then calculate crc of archive without that 32 bytes and compare with provided checksum.
The following approach workable for me.
Produce data.zip
Compute checksum of data.zip, and write it into checksum.txt
Zip data.zip + checksum.txt together as myapp_12-dec-15.zip
myapp_12-dec-15.zip
|
|____ data.zip
|
|____ checksum.txt

How load and save entire file from blobstore, using only BlobKey?

I want to service file (edit), that user uploaded to server. After saving it to blobstore, I want to load it to memory for editing. After storing file I got BlobKey in return. As I understand, I should use the following method to load it into memory:
byte[] BlobstoreService.fetchData(BlobKey blobKey, long startIndex, long endIndex)
The problem is that I do not know how big the file is, so I do not know what to pass as the endIndex variable. How, having only BlobKey, do I load a file from blobstore, change it, save new version and recive new BlobKey of changed file?
From the javadoc reference, seems like you can load a BlobInfo object that will contain your size. You just need to call
BlobInfoFactory() bif = New BlobInfoFactory();
BlobInfo bi = bif.loadBlobInfo(blobKey);
long size = bi.getSize();

Files not saving correctly on ftp in FTPClient

I'm using FTPClient for uploading files on ftp server. first, I have a TempFile object(no matters what is this object), that have a getBytes() method. this method returns List of bytes:
List<Byte> byteList = tempFile.getBytes();
Byte[] byteObjects= new Byte[byteList.size()];
byte[] byteArray = new byte[byteList.size()];
byteObjects = byteList.toArray(byteObjects);
byteArray = ArrayUtils.toPrimitive(byteObjects);
InputStream stream = new ByteArrayInputStream(byteArray);
ftpClient.storeFile(file.getName()+"."+file.getExtension(), stream);
After executing the last line of code, a file creates successfully with expected name, but when i want to open that file, i see "The image test.jpg can not be displayed, because it contains error" in the browser. What is the problem?
It sounds like you needs to set your ftp client to transmit as binary
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
As per the docs
If the current file type is ASCII, line separators in the file are transparently converted to the NETASCII format

Preserving file checksum after extract from zip in java

This is what I'm trying to accomplish:
1) Calculate the checksum of all files to be added to a zip file. Currently using apache commons io follows:
final Checksum oChecksum = new Adler32();
...
//for every file iFile in folder
long lSum = (FileUtils.checksum(iFile, oChecksum)).getValue();
//store this checksum in a log
2) Compress the folder processed as a zip using the Ant zip task.
3) Extract files from the zip one by one to the specified folder (using both commons io and compression for this), and calculate the checksum of the extracted file:
final Checksum oChecksum = new Adler32();
...
ZipFile myZip = new ZipFile("test.zip");
ZipArchiveEntry zipEntry = myZip.getEntry("checksum.log"); //reads the filename from the log
BufferedInputStream myInputStream = new BufferedInputStream(myZip.getInputStream(zipEntry));
File destFile = new File("/mydir", zipEntry.getName());
lDestFile.createNewFile();
FileUtils.copyInputStreamToFile(myInputStream, destFile);
long newChecksum = FileUtils.checksum(destFile, oChecksum).getValue();
The problem I have is that the value from newChecksum doesn't match the one from the original file. The files' sizes match on disk. Funny thing is that if I run cksum or md5sum commands on both files directly on a terminal, these are the same for both files. The mismatch occurs only from java.
Is this the correct way to approach it or is there any way to preserve the checksum value after extraction?
I also tried using a CheckedInputStream but this also gets me different values from java.
EDIT: This seems related to the Adler32 object used (pre-zip vs unzip checks). If I do "new Adler32()" in the unzip check for every file instead of reusing the same Adler32 for all, I get the correct result.
Are you trying to for all file concatenated? If yes, you need to make sure you're reading them in the same order "checksumed" them.
If no, you need to call checksum.reset() between computing the checksum for each file. You'll notice (in you look at the source) that Adler32 is stateful, which means you're computing the checksum of the file plus all the preceding ones during part one.

Categories