I want to convert the MultipartFile to File and upload this to specified directory on my ec2 instance. Here is the converter method.
private fun convertMultiPartFileToFile(multipartFile: MultipartFile, name: String): File? {
val file = multipartFile.originalFilename?.let { File(it) }
try {
log.info { file?.canWrite() } // logs 'false'
log.info { file?.canExecute() } // logs 'false'
file?.setExecutable(true) // still 'false'
file?.setWritable(true) // still 'false'
file.let {
if (file != null) {
FileOutputStream(file).use { outputStream -> outputStream.write(multipartFile.bytes) }
}
}
} catch (e: IOException) {
throw RuntimeException(e)
}
return file
}
It works locally, but when I try this on my ec2 instance, I got the error
java.lang.RuntimeException: java.io.FileNotFoundException: file.png (Permission denied)
I guess it's because I do not have permission to write to specified file. How can I solve this if file?.setWritable(file) and file?.setExecutable(true) return false.
I run the jar by java -jar path/to/jar
The setWritable method documentation says
* #return {#code true} if and only if the operation succeeded. The
* operation will fail if the user does not have permission to
* change the access permissions of this abstract pathname.
How to get the access permissions to this abstract pathname then?
MultipartFiles do not represent files on the file system while File represents a local file on your system. They are just data that's uploaded.
Hence, multipartFile.originalFilename does not give you the name of any file on your system (except a file with the same name "randomly" exists) but the name of the file the user uploaded (on their system).
If you want to access a MultipartFile as a File, you first need to save it as such:
val file=File("what/ever/file/you.want")//in the directory you want to upload it to
multipartFile.transferTo(file)
//it is now stored in file
This will copy the file to your system.
Related
I am trying to transfer a file using googles Nearby Connections API. Largely I can get all components of the transfer to work so that all of the files data is transferred but the issue is that the files data is then stored in Nearby's scoped storage so I am unable to access it from my app to be able to process that data into the appropriate file type and then save and rename as necessary.
The current method I am using to try and process the payload is
private void processFilePayload(long payloadId) {
// BYTES and FILE could be received in any order, so we call when either the BYTES or the FILE
// payload is completely received. The file payload is considered complete only when both have
// been received.
Payload filePayload = completedFilePayloads.get(payloadId);
String filename = filePayloadFilenames.get(payloadId);
if (filePayload != null && filename != null) {
completedFilePayloads.remove(payloadId);
filePayloadFilenames.remove(payloadId);
// Get the received file (which will be in the Downloads folder)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
File fromPayload = filePayload.asFile().asJavaFile();
Uri uri = Uri.fromFile(fromPayload);
try {
// Copy the file to a new location.
InputStream in = getApplicationContext().getContentResolver().openInputStream(uri);
copyStream(in, new FileOutputStream(new File(getApplicationContext().getCacheDir(), filename)));
} catch (IOException e) {
// Log the error.
Log.e("copy file", e.toString());
} finally {
// Delete the original file.
getApplicationContext().getContentResolver().delete(uri, null, null);
}
} else {
File payloadFile = filePayload.asFile().asJavaFile();
// Rename the file.
payloadFile.renameTo(new File(payloadFile.getParentFile(), filename));
}
}
}
});
Because of android 11's scoped storage to be able to access the file the files Uri needs to be used to create an input stream with a content resolver to access the file.
According to the Nearby Documentation there should be a method Payload.File.asUri so I would be able to use the line Uri payloadUri = filePayload.asFile().asUri(); but this is not actually available in the API despite using the most recent version of Nearby.
As well as this the use of Payload.File.AsJavaFile() should be deprecated according to the google Nearby documentation
I have seen some other answers for similar problems where the suggestion is to use Media.Store but this is not possible as the file does not have any extension yet so doesn't show up as any particular file type.
Note: I have requested read/write external storage permissions both in the manifest and at runtime.
===Update===
Payload.asFile.asUri() is available in com.google.android.gms:play-services-nearby:18.0.0
============
Sorry about that. We'll be releasing an update soon with #asUri properly exposed.
In the meantime, if you target API 29, you can use requestLegacyExternalStorage=true as a workaround. (See more: https://developer.android.com/about/versions/11/privacy/storage)
private void copyFile() throws IOException {
Path destination;
String currentWorkingDir = System.getProperty("user.dir");
File fileToCopy = component.getArchiveServerFile();
if (path.contains(File.separator)) {
destination = Paths.get(path);
} else {
destination = Paths.get(currentWorkingDir + File.separator + path);
}
if (!Files.exists(destination)) {
try {
Files.createDirectories(destination);
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
FileUtils.copyFileToDirectory(fileToCopy, new File(destination.toString()));
}
}
Basically what I'm trying to do here is copying a file in some location using the path provided in the class's constructor. The logic is like this:
If the path has file separator, I consider it a full path and copy the file at the end.
If the path doesn't have file separator, I copy the file in the working directory from which the .exe file was launched.
So far, only the first option works (the full path). For some reason, the working directory option is not working and I can't figure out why.
UPDATE: If I just change the following line:
String currentWorkingDir = System.getProperty("user.dir");
to
String currentWorkingDir = System.getProperty("user.home");
It works. So I'm guessing the problem is coming from user.dir? Maybe at runtime, the folder is already being used and as a result, it can't copy the file into it?
The weird thing is, I don't have any exceptions or error, but nothing happens as well.
UPDATE 2: I think the problem here is that I'm trying to copy a file which is embedded in the application (.exe file) that I'm executing during runtime, and java can't copy it while the current working directory is being used by the application.
UPDATE 3:
Since this copy method is used in an external library, I had to come up with another way (other than logs) to see the content of system property user.dir. So I wrote I little program to create a file and write in it the value return by the property.
To my surprise, the path is not where my application was launched. It was in:
C:\Users\jj\AppData\Local\Temp\2\e4j1263.tmp_dir1602852411
Which is weird because I launched the program from :
C:\Users\jj\workspace\installer\product\target\
Any idea why I'm getting this unexpected value for user.dir?
Is there any way to download google drive file to custom location? I am using this code to get the file,
courses.get(0).getCourseMaterialSets().get(0).getMaterials().get(0).getDriveFile()
This function is returning File type output. How to save it locally?
Or is there any way to download google drive files using classroom API?
I don't think there's a way to do this using Classroom API. To download files from Google Drive, check the download files tutorial using Android API for Drive.
Downloading a file
Preferred method: using alt=media
To download files, you make an authorized HTTP GET request to the
file's resource URL and include the query parameter alt=media. For
example:
GET https://www.googleapis.com/drive/v2/files/0B9jNhSvVjoIVM3dKcGRKRmVIOVU?alt=media
Authorization: Bearer
ya29.AHESVbXTUv5mHMo3RYfmS1YJonjzzdTOFZwvyOAUVhrs Downloading the file
requires the user to have at least read access. Additionally, your app
must be authorized with a scope that allows reading of file content.
For example, an app using the drive.readonly.metadata scope would not
be authorized to download the file contents. Users with edit
permission may restrict downloading by read-only users by setting the
restricted label to true.
Here's a snippet from the guide:
/**
* Download a file's content.
*
* #param service Drive API service instance.
* #param file Drive File instance.
* #return InputStream containing the file's content if successful,
* {#code null} otherwise.
*/
private static InputStream downloadFile(Drive service, File file) {
if (file.getDownloadUrl() != null && file.getDownloadUrl().length() > 0) {
try {
// uses alt=media query parameter to request content
return service.files().get(file.getId()).executeMediaAsInputStream();
} catch (IOException e) {
// An error occurred.
e.printStackTrace();
return null;
}
} else {
// The file doesn't have any content stored on Drive.
return null;
}
}
I have create folder (i.e uploads ) in web application. I want to create one more folder inside "uploads" folder at runtime depends one the username of user. for this i have write below code. This code is creating folder and file but the location is different that i expected.
the location that i am getting is in eclipse location not web application location
D:\PAST\RequiredPlugins\JUNO\eclipse\uploads\datto\adhar.PNG
then i am getting error in FileOutStream that "system can't find the location specified."
public String getFolderName(String folderName, MultipartFile uploadPhoto)
throws ShareMeException {
File uploadfFile = null;
try {
File file = new File("uploads\\" + folderName);
if (!file.exists()) {
file.mkdir();
}
uploadfFile = new File(file.getAbsoluteFile()
+ "\\"+uploadPhoto.getOriginalFilename());
if (uploadfFile.exists()) {
throw new ShareMeException(
"file already exist please rename it");
} else {
uploadfFile.createNewFile();
FileOutputStream fout = new FileOutputStream(uploadfFile);
fout.write(uploadPhoto.getBytes());
fout.flush();
fout.close();
}
} catch (IOException e) {
throw new ShareMeException(e.getMessage());
}
return uploadfFile.getAbsolutePath();
}
i want to save uploaded file in web app "uploads" folder
Your filename is not absolute: uploads\folderName is resolved against the current directory, which the Eclipse launcher sets to JUNO\eclipse.
You should introduce an application variable like APP_HOME and resolve any data directory (including upload) against this variable.
Also, I suggest not to name anything (neither files nor directories) on your filesystem after user-entered input: you are asking for troubles (unicode characters in the user name) and especially security holes (even in combination with the unicode thing). If you really want to use the filesystem, keep the filename anonymous (1.data, 2.data, ...) and keep metadata inside some database.
You can do something on below lines in your webapp:-
String folderPath= request.getServletContext().getRealPath("/");
File file = new File (folderPath+"upload");
file.mkdir();
I've been using Java 7's ZipFS support.
https://gist.github.com/stain/5591420
shows the behaviour, which I find a bit odd. Basically you can create a ZIP file system, make a file with a given name, and then also make a folder with the same name.
The reason for this seems to be that internally the folder gets "/" appended to its name - however this new name is not returned, therefore you end up in a strange situation where Files.isDirectory() returns false immediately after a successful Files.createDirectory().
try (FileSystem fs = tempZipFS()) {
Path folder = fs.getPath("folder");
Files.createFile(folder);
assertTrue(Files.isRegularFile(folder));
assertFalse(Files.isDirectory(folder));
// try {
Files.createDirectory(folder);
// } catch (FileAlreadyExistsException ex) {
// Is not thrown!
// }
// but a second createDirectory() fails correctly
try {
Files.createDirectory(folder);
} catch (FileAlreadyExistsException ex) {
}
// Look, it's both a file and folder!
Path child = folder.resolve("child");
Files.createFile(child);
// Can this be tested?
assertTrue(Files.isRegularFile(folder));
// Yes, if you include the final /
assertTrue(Files.isDirectory(fs.getPath("folder/")));
// But not the parent
// assertTrue(Files.isDirectory(child.getParent()));
// Or the original Path
// assertTrue(Files.isDirectory(folder));
}
So as long as you have the "/" as the suffix, you can even work with both, and that's how they are listed if you do a directory listing of the root.
Now the ZIP format itself allows this as it only deals with entries in a ZIP file (even allowing multiple entries with the same name), however normal use of a "FileSystem" would normally not allow multiple entries with the same name ; as can be seen when I try to create the folder twice.
The produced ZIP file can be browsed correctly with infozip, 7Zip and Windows 8; but trying to unzip will obviously fail because the native file system don't support such duality.
So is this a feature, bug or something in between?