java servlet cos multipart: save inpustream for later storage - java

I am using COS multipart to handle file upload on the servlet.
When processing the parts i need to rename the file with an extra posted field (ParamPart), in this case 'artikelcode' needs to be prepended to the filename.
So instead of directly writing the FilePart to disk i need to save the inputstream in memory.
This is the code i have so far:
MultipartParser multipartParser = new MultipartParser(request, 100000000);
String artikelcode = null;
String filename = null;
InputStream in = null;
while ((part = multipartParser.readNextPart()) != null) {
if (part.isFile()) {
FilePart filePart = (FilePart) part;
filename = filePart.getFileName();
//long fileSize = filePart.writeTo(new File(fileSavePath));
if (filename != null) in = filePart.getInputStream();
}
if (part.isParam()) {
ParamPart paramPart = (ParamPart) part;
if (paramPart.getName().equals("artikelcode")) artikelcode = paramPart.getStringValue();
}
}
if (in != null)
{
String fileSavePath = "c:\\upload\\"+artikelcode+"_"+filename;
File file = new File(fileSavePath);
OutputStream out = new FileOutputStream(file);
IOUtils.copy(in, out);
out.close();
}
When the file is saved on disk, it is empty!
Thanks for your help!!

Calling readNextPart() invalidates any data that you got from the previous part.
Here is a better approach: Always save the file with a temporary name and then rename it.
This allows you to handle a lot of common errors graciously like: Disk full, errors while saving, etc. because you never overwrite existing files until you are 100% sure the new file is complete.

Try to replace double slash with single slash like this..
String fileSavePath = "c:/upload/"+artikelcode+"_"+filename;

Related

How to upload multiple files in Play Framework using Java

Hi i have been trying to upload image file in Play Framework. I have been trying out with Java File Upload since morning but unable to do so. I have seen [JavaFileUpload][1] tutorial available on framework website. But i am still not successful. Here is my code which i am trying to run:
Http.MultipartFormData body = request().body().asMultipartFormData();
List<Http.MultipartFormData.FilePart> fileParts = body.getFiles();
for (Http.MultipartFormData.FilePart filePart : fileParts) {
String filename = filePart.getFilename();
File file = filePart.getFile(); //error comes on this line
if (filePart.getFilename().toLowerCase().endsWith(".png")) {
//saving here but how?
} else {
return badRequest("Invalid request, only PNGs are allowed.");
}
}
but problem is that whenever i try to get the file i am having this conversion error:
java.lang.Object cannot be converted to java.io.File
Anyone can guide me in the direction? if we see the official document there is no proper documentation on how to upload multiple files. If anyone can show me some website which can helps me in that direction that will be also helpful
I'm using Play 2.4 and
FilePart filePart = request().body().asMultipartFormData()
.getFile("myFileKey");
File file = filePart.getFile();
With Play 2.2 I used for multiple file uploads:
MultipartFormData mfd = request().body().asMultipartFormData();
List<FilePart> filePartList = mfd.getFiles();
FilePart filePart = filePartList.get(0);
So after lots of trouble i was able to figure out the answer to my question. Here i am going to post the answer so it helps other people searching the answer to the same problem i faced
The controller function call which will upload the files looks like this:
Http.MultipartFormData body = request().body().asMultipartFormData();
List<Http.MultipartFormData.FilePart> fileParts = body.getFiles();
for (Http.MultipartFormData.FilePart filePart : fileParts) {
if (filePart.getFilename().toLowerCase().endsWith(".png")) {
String filename = filePart.getFilename();
Files.write(Paths.get(filename + ".png"), readContentIntoByteArray((File) filePart.getFile()));
} else {
return badRequest("Invalid request, only PNGs are allowed.");
}
}
I am using a function call to read the content of the file into byte array and save them inside the file:
private static byte[] readContentIntoByteArray(File file) {
FileInputStream fileInputStream = null;
byte[] bFile = new byte[(int) file.length()];
try {
//convert file into array of bytes
fileInputStream = new FileInputStream(file);
fileInputStream.read(bFile);
fileInputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return bFile;
}
Remember you can choose whatever the path you want to save the file at Paths.get(filename + ".png")

Getting specific file from ZipInputStream

I can go through ZipInputStream, but before starting the iteration I want to get a specific file that I need during the iteration. How can I do that?
ZipInputStream zin = new ZipInputStream(myInputStream)
while ((entry = zin.getNextEntry()) != null)
{
println entry.getName()
}
If the myInputStream you're working with comes from a real file on disk then you can simply use java.util.zip.ZipFile instead, which is backed by a RandomAccessFile and provides direct access to the zip entries by name. But if all you have is an InputStream (e.g. if you're processing the stream directly on receipt from a network socket or similar) then you'll have to do your own buffering.
You could copy the stream to a temporary file, then open that file using ZipFile, or if you know the maximum size of the data in advance (e.g. for an HTTP request that declares its Content-Length up front) you could use a BufferedInputStream to buffer it in memory until you've found the required entry.
BufferedInputStream bufIn = new BufferedInputStream(myInputStream);
bufIn.mark(contentLength);
ZipInputStream zipIn = new ZipInputStream(bufIn);
boolean foundSpecial = false;
while ((entry = zin.getNextEntry()) != null) {
if("special.txt".equals(entry.getName())) {
// do whatever you need with the special entry
foundSpecial = true;
break;
}
}
if(foundSpecial) {
// rewind
bufIn.reset();
zipIn = new ZipInputStream(bufIn);
// ....
}
(I haven't tested this code myself, you may find it's necessary to use something like the commons-io CloseShieldInputStream in between the bufIn and the first zipIn, to allow the first zip stream to close without closing the underlying bufIn before you've rewound it).
use the getName() method on ZipEntry to get the file you want.
ZipInputStream zin = new ZipInputStream(myInputStream)
String myFile = "foo.txt";
while ((entry = zin.getNextEntry()) != null)
{
if (entry.getName().equals(myFileName)) {
// process your file
// stop looking for your file - you've already found it
break;
}
}
From Java 7 onwards, you are better off using ZipFile instead of ZipStream if you only want one file and you have a file to read from:
ZipFile zfile = new ZipFile(aFile);
String myFile = "foo.txt";
ZipEntry entry = zfile.getEntry(myFile);
if (entry) {
// process your file
}
Look at Finding a file in zip entry
ZipFile file = new ZipFile("file.zip");
ZipInputStream zis = searchImage("foo.png", file);
public searchImage(String name, ZipFile file)
{
for (ZipEntry e : file.entries){
if (e.getName().endsWith(name)){
return file.getInputStream(e);
}
}
return null;
}
I'm late to the party, but all above "answers" does not answer the question and accepted "answer" suggest create temp file which is inefficient.
Lets create sample zip file:
seq 10000 | sed "s/^.*$/a/"> /tmp/a
seq 10000 20000 | sed "s/^.*$/b/"> /tmp/b
seq 20000 30000 | sed "s/^.*$/c/"> /tmp/c
zip /tmp/out.zip /tmp/a /tmp/b /tmp/c
so now we have /tmp/out.zip file, which contains 3 files, each of them full of chars a, b or c.
Now lets read it:
public static void main(String[] args) throws IOException {
ZipInputStream zipStream = new ZipInputStream(new FileInputStream("/tmp/out.zip"));
ZipEntry zipEntry;
while ((zipEntry = zipStream.getNextEntry()) != null) {
String name = zipEntry.getName();
System.out.println("Entry: "+name);
if (name.equals("tmp/c")) {
byte[] bytes = zipStream.readAllBytes();
String s = new String(bytes);
System.out.println(s);
}
}
}
method readAllBytes seems weird, while we're in processing of stream, but it seems to work, I tested it also on some images, where there is higher chance of failure. So it's probably just unintuitive api, but it seems to work.

How do parse some files in a tar.bz2 archive with Java

So I have written the parser for parsing an individual file but can i read each file within the archive without having to actually extract the archive to disk
Following the examples in http://commons.apache.org/proper/commons-compress/examples.html you have to wrap one InputStream with another
// 1st InputStream from your compressed file
FileInputStream in = new FileInputStream(tarbz2File);
// wrap in a 2nd InputStream that deals with compression
BZip2CompressorInputStream bzIn = new BZip2CompressorInputStream(in);
// wrap in a 3rd InputStream that deals with tar
TarArchiveInputStream tarIn = new TarArchiveInputStream(bzIn);
ArchiveEntry entry = null;
while (null != (entry = tarIn.getNextEntry())){
if (entry.getSize() < 1){
continue;
}
// use your parser here, the tar inputStream deals with the size of the current entry
parser.parse(tarIn);
}
tarIn.close();

Reading directly from Google Drive in Java

Please I need to read the content of a file stored in Google Drive programmatically. I'm looking forward to some sort of
InputStream is = <drive_stuff>.read(fileID);
Any help?
I'll also appreciate if I can write back to a file using some sort of
OutputStream dos = new DriveOutputStream(driveFileID);
dos.write(data);
If this sort of convenient approach is too much for what Drive can offer, please I'll like to have suggestions on how I can read/write to Drive directly from java.io.InputStream / OutputStream / Reader / Writer without creating temporary local file copies of the data I want to ship to drive. Thanks!
// Build a new authorized API client service.
Drive service = getDriveService();
// Print the names and IDs for up to 10 files.
FileList result = service.files().list()
.setPageSize(10)
.setFields("nextPageToken, files(id, name)")
.execute();
List<File> files = result.getFiles();
if (files == null || files.size() == 0) {
System.out.println("No files found.");
} else {
System.out.println("Files:");
for (File file : files) {
System.out.printf("%s (%s)\n", file.getName(), file.getId());
String fileId = file.getId();
Export s=service.files().export(fileId, "text/plain");
InputStream in=s.executeMediaAsInputStream();
InputStreamReader isr=new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);
String line = null;
StringBuilder responseData = new StringBuilder();
while((line = br.readLine()) != null) {
responseData.append(line);
}
System.out.println(responseData);
}
}
}
Please take a look at the DrEdit Java sample that is available on the Google Drive SDK documentation.
This example shows how to authorize and build requests to read metadata, file's data and upload content to Google Drive.
Here is a code snippet showing how to use the ByteArrayContent to upload media to Google Drive stored in a byte array:
/**
* Create a new file given a JSON representation, and return the JSON
* representation of the created file.
*/
#Override
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
Drive service = getDriveService(req, resp);
ClientFile clientFile = new ClientFile(req.getReader());
File file = clientFile.toFile();
if (!clientFile.content.equals("")) {
file = service.files().insert(file,
ByteArrayContent.fromString(clientFile.mimeType, clientFile.content))
.execute();
} else {
file = service.files().insert(file).execute();
}
resp.setContentType(JSON_MIMETYPE);
resp.getWriter().print(new Gson().toJson(file.getId()).toString());
}
Here's a (incomplete) snippet from my app which might help.
URL url = new URL(urlParam);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("GET");
connection
.setRequestProperty("Authorization",
"OAuth "+accessToken);
String docText = convertStreamToString(connection.getInputStream());
Using google-api-services-drive-v3-rev24-java-1.22.0:
To read the contents of a file, make sure you set DriveScopes.DRIVE_READONLY when you do GoogleAuthorizationCodeFlow.Builder(...) in your credential authorizing method/code.
You'll need the fileId of the file you want to read. You can do something like this:
FileList result = driveService.files().list().execute();
You can then iterate the result for the file and fileId you want to read.
Once you have done that, reading the contents would be something like this:
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
driveService.files().get(fileId).executeMediaAndDownloadTo(outputStream);
InputStream in = new ByteArrayInputStream(outputStream.toByteArray());

How do i get a filename of a file inside a gzip in java?

int BUFFER_SIZE = 4096;
byte[] buffer = new byte[BUFFER_SIZE];
InputStream input = new GZIPInputStream(new FileInputStream("a_gunzipped_file.gz"));
OutputStream output = new FileOutputStream("current_output_name");
int n = input.read(buffer, 0, BUFFER_SIZE);
while (n >= 0) {
output.write(buffer, 0, n);
n = input.read(buffer, 0, BUFFER_SIZE);
}
}catch(IOException e){
System.out.println("error: \n\t" + e.getMessage());
}
Using the above code I can succesfully extract a gzip's contents although the extracted file's filenames are, as expected, will always be current_output_name (I know its because I declared it to be that way in the code). My problem is I dont know how to get the file's filename when it is still inside the archive.
Though, java.util.zip provides a ZipEntry, I couldn't use it on gzip files.
Any alternatives?
as i kinda agree with "Michael Borgwardt" on his reply, but it is not entirely true, gzip file specifications contains an optional file name stored in the header of the gz file, sadly there are no way (as far as i know ) of getting that name in current java (1.6). as seen in the implementation of the GZIPInputStream in the method getHeader in the openjdk
they skip reading the file name
// Skip optional file name
if ((flg & FNAME) == FNAME) {
while (readUByte(in) != 0) ;
}
i have modified the class GZIPInputStream to get the optional filename out of the gzip archive(im not sure if i am allowed to do that) (download the original version from here), you only need to add a member String filename; to the class, and modify the above code to be :
// Skip optional file name
if ((flg & FNAME) == FNAME) {
filename= "";
int _byte = 0;
while ((_byte= readUByte(in)) != 0){
filename += (char)_byte;
}
}
and it worked for me.
Apache Commons Compress offers two options for obtaining the filename:
With metadata (Java 7+ sample code)
try ( //
GzipCompressorInputStream gcis = //
new GzipCompressorInputStream( //
new FileInputStream("a_gunzipped_file.gz") //
) //
) {
String filename = gcis.getMetaData().getFilename();
}
With "the convention"
String filename = GzipUtils.getUnCompressedFilename("a_gunzipped_file.gz");
References
Apache Commons Compress
GzipCompressorInputStream
See also: GzipUtils#getUnCompressedFilename
Actually, the GZIP file format, using the multiple members, allows the original filename to be specified. Including a member with the FLAG of FLAG.FNAME the name can be specified. I do not see a way to do this in the java libraries though.
http://www.gzip.org/zlib/rfc-gzip.html#specification
following the answers above, here is an example that creates a file "myTest.csv.gz" that contains a file "myTest.csv", notice that you can't change the internal file name, and you can't add more files into the gz file.
#Test
public void gzipFileName() throws Exception {
File workingFile = new File( "target", "myTest.csv.gz" );
GZIPOutputStream gzipOutputStream = new GZIPOutputStream( new FileOutputStream( workingFile ) );
PrintWriter writer = new PrintWriter( gzipOutputStream );
writer.println("hello,line,1");
writer.println("hello,line,2");
writer.close();
}
Gzip is purely compression. There is no archive, it's just the file's data, compressed.
The convention is for gzip to append .gz to the filename, and for gunzip to remove that extension. So, logfile.txt becomes logfile.txt.gz when compressed, and again logfile.txt when it's decompressed. If you rename the file, the name information is lost.

Categories

Resources