How to update already existing file in google drive api v3 java - java

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();

Related

Download multiple files(stored in a database) in a zip in java

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
}

Uploading files to S3 in Spring boot and getting stored them in classpath

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.

AWS S3 upload file name mismatch

I am able to upload multiple files to s3 bucket at once. However there is a mismatch in the file name the one I provided and uploaded file. I am interested in file name as I need to generate cloud front signed url based on that.
File generation code
final String fileName = System.currentTimeMillis() + pictureData.getFileName();
final File file = new File(fileName); //fileName is -> 1594125913522_image1.png
writeByteArrayToFile(img, file);
AWS file upload code
public void uploadMultipleFiles(final List<File> files) {
final TransferManager transferManager = TransferManagerBuilder.standard().withS3Client(amazonS3).build();
try {
final MultipleFileUpload xfer = transferManager.uploadFileList(bucketName, null, new File("."), files);
xfer.waitForCompletion();
} catch (InterruptedException exception) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("InterruptedException occurred=>" + exception);
}
} catch (AmazonServiceException exception) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("AmazonServiceException occurred =>" + exception);
}
throw exception;
}
}
Uploaded file name is 94125913522_image1.png. As you can see first two characters disappeared. What am I missing here. I am not able to figure out. Kindly advice.
private static void writeByteArrayToFile(final byte[] byteArray, final File file) {
try (OutputStream outputStream = new BufferedOutputStream(Files.newOutputStream(Paths.get(file.getName())))) {
outputStream.write(byteArray);
} catch (IOException exception) {
throw new FileIllegalStateException("Error while writing image to file", exception);
}
}
The reason of the problem
You lose the first two charecters of the file names because of the third argument of this method:
transferManager.uploadFileList(bucketName, null, new File("."), files);
What happens in this case
So, what is the third argument:
/**
...
* #param directory
* The common parent directory of files to upload. The keys
* of the files in the list of files are constructed relative to
* this directory and the virtualDirectoryKeyPrefix.
...
*/
public MultipleFileUpload uploadFileList(... , File directory, ...){...}
And how will it be used:
...
int startingPosition = directory.getAbsolutePath().length();
if (!(directory.getAbsolutePath().endsWith(File.separator)))
startingPosition++;
...
String key = f.getAbsolutePath().substring(startingPosition)...
Thus, the directory variable is used to define a starting index to trim file paths to get file keys.
When you pass new File(".") as a directory, the parent directory for your files will be {your_path}.
But this is a directory, and you need to work with files inside it. So the common part, retrieved from your directory file, is {your_path}./
That is 2 symbols more than you actually need. And for this reason this method trims the 2 extra characters - an extra shift of two characters when trimming the file path.
The solution
If you only need to work with the current directory, you can pass the current directory as follows:
MultipleFileUpload upload = transferManager.uploadFileList(bucketName, "",
System.getProperty("user.dir"), files);
But if you start working with external sources, it won't work. So you can use this code, which creates one MultipleFileUpload per group of files from one directory.
private final String PATH_SEPARATOR = File.separator;
private String bucketName;
private TransferManager transferManager;
public void uploadMultipleFiles(String prefix, List<File> filesToUpload){
Map<File, List<File>> multipleUploadArguments =
getMultipleUploadArguments(filesToUpload);
for (Map.Entry<File, List<File>> multipleUploadArgument:
multipleUploadArguments.entrySet()){
try{
MultipleFileUpload upload = transferManager.uploadFileList(
bucketName, prefix,
multipleUploadArgument.getKey(),
multipleUploadArgument.getValue()
);
upload.waitForCompletion();
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
}
}
private Map<File, List<File>> getMultipleUploadArguments(List<File> filesToUpload){
return filesToUpload.stream()
.collect(Collectors.groupingBy(this::getDirectoryPathForFile));
}
private File getDirectoryPathForFile(File file){
String filePath = file.getAbsolutePath();
String directoryPath = filePath.substring(0, filePath.lastIndexOf(PATH_SEPARATOR));
return new File(directoryPath);
}

Google Drive API v3- create a folder inside a folder in Java

I'm trying to develop a method in Java that enables creating a folder inside of a specific folder in Google Drive, but what I found in Google documentation (https://developers.google.com/drive/api/v3/folder) is creating only a folder or moving a file to a folder.
Any help would be appreciated!
Just take what the API gave you for creating a folder and inserting a file in a folder and combine them.
From the API site: 'The parents property can be used when creating a folder as well to create a subfolder.'
String folderId = "folderID";
File fileMetadata = new File();
fileMetadata.setName("Invoices");
fileMetadata.setParents(Collections.singletonList(folderId));
fileMetadata.setMimeType("application/vnd.google-apps.folder");
File file = driveService.files().create(fileMetadata)
.setFields("id, parent")
.execute();
System.out.println("Folder ID: " + file.getId());
You need to create a drive service first. Then you can call createSubFolder method.
// Build a new authorized API client service.
final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
Drive driveService = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT))
.setApplicationName(APPLICATION_NAME)
.build();
Resource Link: https://developers.google.com/drive/api/v3/quickstart/java
Here,
It is required to give id of parent folder.
And have to give the sub folder name.
public String createSubFolder(String parentFolderId, String subFolderName) {
System.out.println("Sub Folder Name: "+subFolderName);
File file = null;
try {
File fileMetadata = new File();
fileMetadata.setName(subFolderName);
fileMetadata.setMimeType("application/vnd.google-apps.folder");
if (parentFolderId != null) {
List<String> parents = Arrays.asList(parentFolderId);
fileMetadata.setParents(parents);
}
file = driveService.files().create(fileMetadata).setFields("id, name").execute();
System.out.println("Folder ID: " + file.getId());
return file.getId();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
In case you want to create a folder in a shared drive you have to specify following:
drive id (to file metadata)
supports all drives (to the files().create().setFields in builder chain)
private String createFolder(String folderName, String parent) throws IOException {
System.out.println("Creating folder " + folderName + " in " + parent);
File fileMetadata = new File();
fileMetadata.setParents(Arrays.asList(parent));
fileMetadata.setName(folderName);
fileMetadata.setDriveId(DRIVE_ID);
fileMetadata.setMimeType("application/vnd.google-apps.folder");
File file = drive.files().create(fileMetadata)
.setSupportsAllDrives(true)
.setFields("id")
.execute();
System.out.println("created folder ID: " + file.getId());
return file.getId();
}

upload file into google drive using java api

DocsService client = new DocsService("service name");
client.setUserCredentials(username,password);
File file = new File(filename);
URL url = new URL("https://docs.google.com/feeds/default/private/full/?ocr=true&convert=true");
String mimeType = DocumentListEntry.MediaType.fromFileName(file.getName()).getMimeType();
DocumentEntry newDocument = new DocumentEntry();
newDocument.setTitle(new PlainTextConstruct(file.getName()));
newDocument.setMediaSource(new MediaFileSource(file, mimeType));
//newDocument.setFile(file, mimeType);
newDocument = client.insert(url, newDocument);
System.out.println("uploaded "+file.getName());
JOptionPane.showMessageDialog(null, "uploaded "+file.getName(), "alert", JOptionPane.ERROR_MESSAGE);
using this code i upload file but that file is upload as a document.
means i upload any type of that file is upload as a document in to google drive
As far as I know (its been a few month since I looked) this is not (yet?) supported by the google drive API.
As a workaround consider installing the native google drive share and write the files you want to upload into the locally mapped shared folder. Then its google drives problem to handle the upload.
can guide you with this
<input id="file-pdf" type="file" name="file-pdf">
<button id="submit-pdf">submit</button>
//javascripts
$("#submit-pdf").click(function() {
var inputFileImage = document.getElementById("file-pdf");
var file = inputFileImage.files[0];
var data = new FormData();
data.append("file-pdf",file);
$.ajax({
url: "uploadpdf",
type: 'POST',
cache : false,
data : data,
processData : false,
contentType : false,
dataType: "json",
success: function (response) {
if(response.success){
console.log("ok");
}else{
console.log("fail");
}
}
});
});
for servlet here
function to save to drive
//parentId ID folder drive
public static File insertFile(GoogleCredential credential,String title, String parentId, String mimeType, String filename, InputStream stream) {
try {
Drive driveService = new Drive.Builder(httpTransport, jsonFactory, null).setApplicationName("DRIVE_TEST").setHttpRequestInitializer(credential).build();
// File's metadata.
File body = new File();
body.setTitle(title);
body.setMimeType(mimeType);
// Set the parent folder.
if (parentId != null && parentId.length() > 0) {
body.setParents(
Arrays.asList(new ParentReference().setId(parentId)));
}
// File's content.
InputStreamContent mediaContent = new InputStreamContent(mimeType, new BufferedInputStream(stream));
try {
File file = driveService.files().insert(body, mediaContent).execute();
return file;
} catch (IOException e) {
logger.log(Level.WARNING, "un error en drive service: "+ e);
return null;
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
return null;
}
}
I know this question is quite old ,but now google has official support for Java drive api,there is a quick sample to start integrating Drive API with java application.
Download drive API client jar files from here
and if you are developing your application from Java SE don't forget to put servlet api.jar on class path or else you will end up with lot of errors.

Categories

Resources