Converting MultipartFile to java.io.File without copying to local machine - java

I have a Java Spring MVC web application. From client, through AngularJS, I am uploading a file and posting it to Controller as webservice.
In my Controller, I am gettinfg it as MultipartFile and I can copy it to local machine.
But I want to upload the file to Amazone S3 bucket. So I have to convert it to java.io.File. Right now what I am doing is, I am copying it to local machine and then uploading to S3 using jets3t.
Here is my way of converting in controller
MultipartHttpServletRequest mRequest=(MultipartHttpServletRequest)request;
Iterator<String> itr=mRequest.getFileNames();
while(itr.hasNext()){
MultipartFile mFile=mRequest.getFile(itr.next());
String fileName=mFile.getOriginalFilename();
fileLoc="/home/mydocs/my-uploads/"+date+"_"+fileName; //date is String form of current date.
Then I am using FIleCopyUtils of SpringFramework
File newFile = new File(fileLoc);
// if the directory does not exist, create it
if (!newFile.getParentFile().exists()) {
newFile.getParentFile().mkdirs();
}
FileCopyUtils.copy(mFile.getBytes(), newFile);
So it will create a new file in the local machine. That file I am uplaoding in S3
S3Object fileObject = new S3Object(newFile);
s3Service.putObject("myBucket", fileObject);
It creates file in my local system. I don't want to create.
Without creating a file in local system, how to convert a MultipartFIle to java.io.File?

MultipartFile, by default, is already saved on your server as a file when user uploaded it.
From that point - you can do anything you want with this file.
There is a method that moves that temp file to any destination you want.
http://docs.spring.io/spring/docs/3.0.x/api/org/springframework/web/multipart/MultipartFile.html#transferTo(java.io.File)
But MultipartFile is just API, you can implement any other MultipartResolver
http://docs.spring.io/spring/docs/3.0.x/api/org/springframework/web/multipart/MultipartResolver.html
This API accepts input stream and you can do anything you want with it. Default implementation (usually commons-multipart) saves it to temp dir as a file.
But other problem stays here - if S3 API accepts a file as a parameter - you cannot do anything with this - you need a real file. If you want to avoid creating files at all - create you own S3 API.

The question is already more than one year old, so I'm not sure if the jets35 link provided by the OP had the following snippet at that time.
If your data isn't a File or String you can use any input stream as a data source, but you must manually set the Content-Length.
// Create an object containing a greeting string as input stream data.
String greeting = "Hello World!";
S3Object helloWorldObject = new S3Object("HelloWorld2.txt");
ByteArrayInputStream greetingIS = new ByteArrayInputStream(greeting.getBytes());
helloWorldObject.setDataInputStream(greetingIS);
helloWorldObject.setContentLength(
greeting.getBytes(Constants.DEFAULT_ENCODING).length);
helloWorldObject.setContentType("text/plain");
s3Service.putObject(testBucket, helloWorldObject);
It turns out you don't have to create a local file first. As #Boris suggests you can feed the S3Object with the Data Input Stream, Content Type and Content Length you'll get from MultipartFile.getInputStream(), MultipartFile.getContentType() and MultipartFile.getSize() respectively.

Instead of copying it to your local machine, you can just do this and replace the file name with this:
File newFile = new File(multipartFile.getOriginalName());
This way, you don't have to have a local destination create your file

if you are try to use in httpentity check my answer here
https://stackoverflow.com/a/68022695/7532946

Related

How to convert MultipartFile properly to match for Microsoft AudioConfig?

In my Spring Boot application, I accept an audiofile as MultipartFile with #RequestParam. I know, I can convert the file into some InputStream. I am also able to convert it into some byte array:
#PostMapping("/microsoft")
void transcribe(#RequestParam("file") MultipartFile file) {
InputStream inputStream = new BufferedInputStream(file.getInputStream());
byte[] byteArr = file.getBytes();
AudioConfig audioConfig = AudioConfig.???; //here the correct method with my file needs to be called
}
For transcription using Microsoft API, I need to create some Audioconfig object. This is the link to the class.
I used in the past fromWavFileInput(...) when I loaded a local audio file. But now, I need to be able to use the MultipartFile. I have no idea which method of the AudioConfig class I can use and how to convert the file correctly.
The idea is, to create a temp file and transfer the MultipartFile into it:
File tempFile = File.createTempFile("prefix-", "-suffix");
file.transferTo(tempFile);
The use fromWavFileOutput with the path of the temporary file:
AudioConfig audioConfig = AudioConfig.fromWavFileOutput(tempFile.getPath());
For me, the temp file exceeds its maximum permitted size. To get this solved, make sure to add spring.servlet.multipart.max-file-size=-1 in your application.properties file to set limit to infinity.

MockMultipartFile not working in real environment, as it is available in test package of spring. Is there any workaround for this?

I have a file on my local disk, I want to convert that file to multipart file as I need to upload this file to another server. I am converting file to multipart file using MockMultipartFile, but it is not working as this package is only available in the test environment
I am trying to use CommonsMultipartFile instead of MockMultipartFile, but CommonsMultipartFile constructor needs an object of file item. I am not able to utilize that constructor
Using MockMultipartFile::
FileInputStream fileInputStream = new FileInputStream(unzippedFile);
return new MockMultipartFile(FILE_STRING, unzippedFile.getName(), MULTIPART_FORM_DATA_VALUE, IOUtils.toByteArray(fileInputStream))
Using CommonsMultipartFile::
DiskFileItem diskFileItem = new DiskFileItem(FILE_STRING, MULTIPART_FORM_DATA_VALUE, false, unzippedFile.getName(), (int) unzippedFile.length(), unzippedFile.getParentFile());
diskFileItem.getOutputStream();
MultipartFile multipartFile = new CommonsMultipartFile(diskFileItem);
I expect CommonsMultipartFile constructor to take diskFileItem, but it is giving an error

Download the files inside compressed .gz files from S3 Bucket

I have a set of .gz compressed files in s3 bucket. I want to download the csv file inside the .gz file. I tried to extract the .gz file and put it into the s3Object. Now i need to extract the s3 object and download the csv file inside it using java. Please advise.This is the code I used.Now i am able to download gz file. But I need to download csv file inside gz.
S3Object object = s3Client.getObject(“bucket”,“Location/file.gz”);
final String encoding = null;
return ResponseEntity.ok(IOUtils.toString(object.getObjectContent(), encoding));
I need help in unzipping the gz file in s3object and return the decompressed contents in the response.
The below code will convert your gunzip file into plain data, but I'm not sure 100% about your actual issue, whether you want to display the content in browser itself or you want to send it as Save as Option, that's why I did a minimum code change to your code assuming you have only problem in converting gunzip format to CSV data, hope you could modify/enhance it that suits you best.
import java.util.zip.GZIPInputStream;
//your method begins from here
final AmazonS3 s3 = AmazonS3ClientBuilder.defaultClient();
S3Object object = s3.getObject("your-bucket", "file-path");
return ResponseEntity.ok(IOUtils.toString(new GZIPInputStream(object.getObjectContent())));

Create multiple empty directories in Amazon S3 using java

I am new to S3 and I am trying to create multiple directories in Amazon S3 using java by only making one call to S3.
I could only come up with this :-
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(0);
InputStream emptyContent = new ByteArrayInputStream(new byte[0]);
PutObjectRequest putObjectRequest = new PutObjectRequest(bucket,
"test/tryAgain/", emptyContent, metadata);
s3.putObject(putObjectRequest);
But the problem with this while uploading 10 folders (when the key ends with "/" in the console we can see the object as a folder ) is that I have to make 10 calls to S3.
But I want to do a create all the folders at once like we do a batch delete using DeleteObjectsRequest.
Can anyone please suggest me or help me how to solve my problem ?
Can you be a bit more specific as to what you're trying to do (or avoid doing)?
If you're primarily concerned with the cost per PUT, I don't think there is a way to batch 'upload' a directory with each file being a separate key and avoid that cost. Each PUT (even in a batch process) will cost you the price per PUT.
If you're simply trying to find a way to efficiently and recursively upload a folder, check out the uploadDirectory() method of TransferManager.
http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/transfer/TransferManager.html#uploadDirectory-java.lang.String-java.lang.String-java.io.File-boolean-
public MultipleFileUpload uploadDirectory(String bucketName,
String virtualDirectoryKeyPrefix,
File directory,
boolean includeSubdirectories)

How can fix this error while trying to upload a file to a online database using JSF 2.2? [duplicate]

I would like to be able to upload files in my JSF2.2 web application, so I started using the new <h:inputFile> component.
My only question is, how can I specify the location, where the files will be saved in the server? I would like to get hold of them as java.io.File instances. This has to be implemented in the backing bean, but I don't clearly understand how.
JSF won't save the file in any predefined location. It will basically just offer you the uploaded file in flavor of a javax.servlet.http.Part instance which is behind the scenes temporarily stored in server's memory and/or temporary disk storage location which you shouldn't worry about.
Important is that you need to read the Part as soon as possible when the bean action (listener) method is invoked. The temporary storage may be cleared out when the HTTP response associated with the HTTP request is completed. In other words, the uploaded file won't necessarily be available in a subsequent request.
So, given a
<h:form enctype="multipart/form-data">
<h:inputFile value="#{bean.uploadedFile}">
<f:ajax listener="#{bean.upload}" />
</h:inputFile>
</h:form>
You have basically 2 options to save it:
1. Read all raw file contents into a byte[]
You can use InputStream#readAllBytes() for this.
private Part uploadedFile; // +getter+setter
private String fileName;
private byte[] fileContents;
public void upload() {
fileName = Paths.get(uploadedFile.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
try (InputStream input = uploadedFile.getInputStream()) {
fileContents = input.readAllBytes();
}
catch (IOException e) {
// Show faces message?
}
}
Note the Path#getFileName(). This is a MSIE fix as to obtaining the submitted file name. This browser incorrectly sends the full file path along the name instead of only the file name.
In case you're not on Java 9 yet and therefore can't use InputStream#readAllBytes(), then head to Convert InputStream to byte array in Java for all other ways to convert InputStream to byte[].
Keep in mind that each byte of an uploaded file costs one byte of server memory. Be careful that your server don't exhaust of memory when users do this too often or can easily abuse your system in this way. If you want to avoid this, better use (temporary) files on local disk file system instead.
2. Or, write it to local disk file system
In order to save it to the desired location, you need to get the content by Part#getInputStream() and then copy it to the Path representing the location.
private Part uploadedFile; // +getter+setter
private File savedFile;
public void upload() {
String fileName = Paths.get(uploadedFile.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
savedFile = new File(uploads, fileName);
try (InputStream input = file.getInputStream()) {
Files.copy(input, savedFile.toPath());
}
catch (IOException e) {
// Show faces message?
}
}
Note the Path#getFileName(). This is a MSIE fix as to obtaining the submitted file name. This browser incorrectly sends the full file path along the name instead of only the file name.
The uploads folder and the filename is fully under your control. E.g. "/path/to/uploads" and Part#getSubmittedFileName() respectively. Keep in mind that any existing file would be overwritten, you might want to use File#createTempFile() to autogenerate a filename. You can find an elaborate example in this answer.
Do not use Part#write() as some prople may suggest. It will basically rename the file in the temporary storage location as identified by #MultipartConfig(location). Also do not use ExternalContext#getRealPath() in order to save the uploaded file in deploy folder. The file will get lost when the WAR is redeployed for the simple reason that the file is not contained in the original WAR. Always save it on an absolute path outside the deploy folder.
For a live demo of upload-and-preview feature, check the demo section of the <o:inputFile> page on OmniFaces showcase.
See also:
Write file into disk using JSF 2.2 inputFile
How to save uploaded file in JSF
Recommended way to save uploaded files in a servlet application

Categories

Resources