How to download multiple files in a zip folder. I am using spring-boot and documents are saved in MongoDB using GridFS.
I was trying to download using FileSystemResource which takes File as an argument taking reference from https://simplesolution.dev/spring-boot-download-multiple-files-as-zip-file/
I tried to get download a resource from mongodb using below line of code and convert it into File object using
gridFsTemplate.getResource(GridFsFile).getFile();
I but it throws an error saying
GridFS resource can not be resolved to an absolute file path.
I have done using ByteArrayResource:
public void downloadZipFile(HttpServletResponse response, List<String> listOfDocIds) {
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=download.zip");
List<FileResponse> listOfFiles = myService.bulkDownload(listOfDocIds);// This call will fetch docs in the form of byte[] based on docIds.
try(ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream())) {
for(FileResponse fileName : listOfFiles) {
ByteArrayResource fileSystemResource = new ByteArrayResource(fileName.getFileAsBytes);
ZipEntry zipEntry = new ZipEntry(fileName.getFileName());
zipEntry.setSize(fileSystemResource.contentLength());
zipEntry.setTime(System.currentTimeMillis());
zipOutputStream.putNextEntry(zipEntry);
StreamUtils.copy(fileSystemResource.getInputStream(), zipOutputStream);
zipOutputStream.closeEntry();
}
zipOutputStream.finish();
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
class FileResponse{
private String fileName;
private byte[] fileAsBytes;
// setter and getters
}
I'm trying to get a midi file through a form in Vaadin, but when I try to get this File into a File class and getting a UnsupportedOperationException. This is happening in the File midiFile = fileData.getFile();
java.lang.UnsupportedOperationException: class java.io.ByteArrayOutputStream not supported. Use a UploadOutputStream
In the form it seems that the file has been loaded, but there was an error as trying to generate the File. I don't know why is this happening as I follow the methods in Vaadin documentation to get the file from the Upload. And I don't understand why it says in this exception "Happens if outputBuffer is not an UploadOutputStream".
https://vaadin.com/api/platform/23.0.9/com/vaadin/flow/component/upload/receivers/FileData.html
And if I run getFileName() from FileData after getting it from the MemoryBuffer I see that the recently uploaded file is there.
https://vaadin.com/api/platform/23.0.9/com/vaadin/flow/component/upload/receivers/MemoryBuffer.html
This is the full code.
import com.vaadin.flow.component.upload.Upload;
import com.vaadin.flow.component.upload.receivers.FileData;
import com.vaadin.flow.component.upload.receivers.MemoryBuffer;
public MainView() {
MemoryBuffer memoryBuffer = new MemoryBuffer();
Upload midiFileUpload = new Upload(memoryBuffer);
midiFileUpload.setDropLabel(new Label("Upload a file in .mid format"));
midiFileUpload.addSucceededListener(event -> {
InputStream inputFileData = memoryBuffer.getInputStream();
String fileName = event.getFileName();
long contentLength = event.getContentLength();
String mimeType = event.getMIMEType();
FileData fileData = memoryBuffer.getFileData();
try {
File midiFile = fileData.getFile();
} catch (UnsupportedOperationException uoe) {
System.out.println("OutputBuffer is not an UploadOutputStream.");
uoe.printStackTrace();
} catch (NullPointerException npe) {
System.out.println("Empty buffer.");
npe.printStackTrace();
}
});
}
As the name implies, MemoryBuffer stores the uploaded file in memory, so it can't provide a java.io.File, only an InputStream to read the data from. If you want Upload to use a (temporary!) file, use a FileBuffer instead.
I don't know why this issue is happening but I solved it just changing from MemoryBuffer to FileBuffer class. Now it works.
I have method to upload files from user to S3 bucket. But when I'm testing it, it is both saved on S3 buckend and in my classpath.
This is my function to upload file:
public void uploadFileToNews(byte[] file, String fileName) {
File fileToSave = new File(fileName);
try(FileOutputStream fileOutputStream = new FileOutputStream(fileToSave) ) {
fileOutputStream.write(file);
amazonS3.putObject(new PutObjectRequest("gwnews", fileName, fileToSave));
} catch (IOException e) {
log.error("Error during uploading file to S3", e);
}
}
And this is function in my service:
public News addNewsImage(MultipartFile multipartFile, String newsId) throws IOException {
News news = getById(newsId);
news.setImageUrl(news.getId() + ".png");
fileService.uploadFileToNews(multipartFile.getBytes(), news.getId() + ".png");
return newsRepository.save(news);
}
Am I doing something wrong? How can I avoid saving file to my classpath?
This line is saving the content in your classpath : "fileOutputStream.write(file);"
And the next line is saving it in your S3 bucket for corresponding AWS account.
I have tried with the following code... Without any luck...
private void updateFile(Drive service, String fileId) {
try {
File file = new File(); /********/
final java.io.File fileToUpdate = new java.io.File("D:/Work Data/Files/pdf.pdf");
FileContent mediaContent = new FileContent("image/pdf", fileToUpdate);
file = service.files().update(fileId, file, mediaContent).execute();
System.out.println(fileId);
} catch (Exception e) {
if (isDebug) {
e.printStackTrace();
}
}
}
also tried with...
private void updateFile(Drive service, String fileId) {
try {
File file = service.files().get(fileId).execute(); /********/
final java.io.File fileToUpdate = new java.io.File("D:/Work Data/Files/pdf.pdf");
FileContent mediaContent = new FileContent("image/pdf", fileToUpdate);
file = service.files().update(fileId, file, mediaContent).execute();
System.out.println(fileId);
} catch (Exception e) {
if (isDebug) {
e.printStackTrace();
}
}
}
With every time i execute the code i get the following stacktrace:
java.lang.IllegalArgumentException
at com.google.api.client.repackaged.com.google.common.base.Preconditions.checkArgument(Preconditions.java:111)
at com.google.api.client.util.Preconditions.checkArgument(Preconditions.java:37)
at com.google.api.client.googleapis.media.MediaHttpUploader.setInitiationRequestMethod(MediaHttpUploader.java:872)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.initializeMediaUpload(AbstractGoogleClientRequest.java:237)
at com.google.api.services.drive.Drive$Files$Update.<init>(Drive.java:3163)
at com.google.api.services.drive.Drive$Files.update(Drive.java:3113)
at com.test.DriveTester.updateFile(DriveTester.java:76)
at com.test.DriveTester.main(DriveTester.java:64)
Can anyone tell what i am doing wrong ? Any sample code for this i.e. updating the content of an already existing file on google drive will be helpful...
For API v3 the solution proposed by Android Enthusiast does not work unfortunately.
The issue is with this bit:
// First retrieve the file from the API.
File file = service.files().get(fileId).execute();
doing this it will create a File object, with it's ID field being set, when executing the update, itt will throw an exception, since the ID meta field is not editable directly.
What you can do is simply create a new file:
File file = new File();
alter the meta you'd like and update file content if required as shown in the example.
then simply update the file as proposed above:
// Send the request to the API.
File updatedFile = service.files().update(fileId, file, mediaContent).execute();
So based a full example would look like this based on Android Enthusiast solution:
private static File updateFile(Drive service, String fileId, String newTitle,
String newDescription, String newMimeType, String newFilename, boolean newRevision) {
try {
// First create a new File.
File file = new File();
// File's new metadata.
file.setTitle(newTitle);
file.setDescription(newDescription);
file.setMimeType(newMimeType);
// File's new content.
java.io.File fileContent = new java.io.File(newFilename);
FileContent mediaContent = new FileContent(newMimeType, fileContent);
// Send the request to the API.
File updatedFile = service.files().update(fileId, file, mediaContent).execute();
return updatedFile;
} catch (IOException e) {
System.out.println("An error occurred: " + e);
return null;
}
}
I can share javascript code for uploading to an already existing file using v3
const url = 'https://www.googleapis.com/upload/drive/v3/files/' + fileId + '?uploadType=media';
if(self.fetch){
var setHeaders = new Headers();
setHeaders.append('Authorization', 'Bearer ' + authToken.access_token);
setHeaders.append('Content-Type', mime);
var setOptions = {
method: 'PATCH',
headers: setHeaders,
body: data
};
fetch(url,setOptions)
.then(response => { if(response.ok){
console.log("save to drive");
}
else{
console.log("Response wast not ok");
}
})
.catch(error => {
console.log("There is an error " + error.message);
});
To update files content, you can use Files:update, this method supports an /upload URI and accepts uploaded media with the following characteristics:
Maximum file size: 5120GB
Accepted Media MIME types: /
This method provides media upload functionality through two separate URIs. For more details, see the document on media upload.
Upload URI, for media upload requests:
PUT https://www.googleapis.com/upload/drive/v2/files/fileId
* Metadata URI, for metadata-only requests:
PUT https://www.googleapis.com/drive/v2/files/fileId
private static File updateFile(Drive service, String fileId, String newTitle,
String newDescription, String newMimeType, String newFilename, boolean newRevision) {
try {
// First retrieve the file from the API.
File file = service.files().get(fileId).execute();
// File's new metadata.
file.setTitle(newTitle);
file.setDescription(newDescription);
file.setMimeType(newMimeType);
// File's new content.
java.io.File fileContent = new java.io.File(newFilename);
FileContent mediaContent = new FileContent(newMimeType, fileContent);
// Send the request to the API.
File updatedFile = service.files().update(fileId, file, mediaContent).execute();
return updatedFile;
} catch (IOException e) {
System.out.println("An error occurred: " + e);
return null;
}
}
You may also check this SO ticket, the ticket discuss the said error.
Source
Unlike the other answers, this solution allows you to upload without having to create a file for the data on the device first.
// Create a File containing any metadata changes.
File metadata = new File().setName(name);
// Convert content to an AbstractInputStreamContent instance.
ByteArrayContent contentStream = ByteArrayContent.fromString("text/plain", content);
// Update the metadata and contents.
mDriveService.files().update(fileId, metadata, contentStream).execute();
I have a servlet which uses file with data. The relative path to this file is contained in web.xml.
I have following part of code, which reads data from file:
public class LoginServlet extends HttpServlet {
private Map<String, UserData> users;
public void init() throws ServletException {
super.init();
String userFilePath = getServletContext().getInitParameter("user.access.file");
InputStream userFile = this.getClass().getResourceAsStream(userFilePath);
try {
users = readUsersFile(userFile);
} catch (IOException e) {
e.printStackTrace();
throw new ServletException(e);
}
....
....
}
private Map<String, UserData> readUsersFile(InputStream is) throws IOException{
BufferedReader fileReader = new BufferedReader(new InputStreamReader(is));
Map<String, UserData> result = new HashMap<String, UserData>();
....
....
....
return result;
}
}
Because this is a servlet and it will not work only on my PC, I can't use absolute path.
Does anyone know how I can write data to the file, using a similar way?
If the resource URL is resolveable to an absolute local disk file system path and it is writable, then you can use
URL url = this.getClass().getResource(userFilePath);
File file = new File(url.toURI().getPath());
OutputStream output = new FileOutputStream(file);
// ...
This is however in turn not guaranteed to work on all environments.
Your best bet is really to have a fixed and absolute local disk file system path. The normal practice is however to store structured data (usernames/password) in a database and not a file.