I have the strangest behavior using the JCIFS SmbFile.renameTo() method. When I execute the code below it should move the network file from test1 to test2, but instead it creates a folder in test2 called test.xml and throws the following error "Cannot create a file when that file already exists..." I can't figure it out. Why is this method doing this?
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication (sDomain,
sUsername, sPassword);
SmbFile smbFromFile = new SmbFile("smb://test1/test.xml", auth);
SmbFile smbToFile = new SmbFile("smb://test2/test.xml", auth);
smbFromFile.renameTo(smbToFile);
There's an interesting difference between copyTo(SmbFile) and renameTo(SmbFile) - only one of them says This file and the destination file do not need to be on the same host. As renameTo(SmbFile) does not say that, I can only assume you should use copyTo and then delete() the original.
SmbFile smbFromFile = new SmbFile("smb://test1/test.xml", auth);
SmbFile smbToFile = new SmbFile("smb://test2/test.xml", auth);
// smbFromFile.renameTo(smbToFile);
smbFromFile.copyTo(smbToFile);
smbFromFile.delete();
There are two possible Scenarios:
1.) The file needs to be moved on the same server ( That is, the authentication details for Input folder and Output folder are same).
Use renameTo() method.
public boolean moveFile(SmbFile file) {
log.info("{"Started Archiving or Moving the file");
String targetFilePath = this.archiveDir + file.getName(); //Path where we need to move that file.
try {
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("", userId, userPassword);
log.info("targetFilePath: {} , currentFile : {}",targetFilePath, file);
SmbFile targetFile = new SmbFile(targetFilePath, auth);
//authenticate the SmbFile
try {
file.renameTo(targetFile); //User renameTo method for same server
log.info("Archived File : {} to: {}", file.getName(),
targetFile.getName());
return true;
} catch (SmbException e) {
log.error("Unable to Archive File: {}", file.getName());
return false;
}
} catch (MalformedURLException e) {
log.error("Connection failed to Server Drive: {}", targetFilePath);
}
return false;
}
2.) The file needs to be moved on Different server ( That is, the authentication details for Input folder and Output folder are NOT same).
Use copyTo() method.
Here I will suggest, You can firstly authenticate the first server on which file is present, And check if the File exists, If it is existing then add that in a list :
public List<SmbFile> xmlFiles = new ArrayList<>(); //Here we will add all the files which are existing.
public boolean isFileExists() throws MalformedURLException, SmbException {
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("",
userID, userPassword); //authenticating input folder.
SmbFile smbFile = new SmbFile(inputFolder, auth);
SmbFile[] smbFiles = smbFile.listFiles();
boolean isFilePresent = false;
if (smbFiles.length > 0) {
for (SmbFile file : smbFiles) {
if (file.getName().toLowerCase(Locale.ENGLISH)
.contains(AppConstant.FILE_NAME.toLowerCase(Locale.ENGLISH))) {
xmlFiles.add(file);
isFilePresent = true;
}
}
}
if (isPlanFilePresent) {
log.info("Number of files present on Server: {}",smbFiles.length);
return true;
}
return false;
}
This will give you the files in the list. Go ahead to copy it to another server. Note that you need to authenticate here for the output Folder only.
public boolean moveFile(SmbFile file) {
log.info("Started Moving or Archiving the file");
String toFilePath = this.outputFolder + file.getName(); //path where you need to copy the file from input folder.
try {
NtlmPasswordAuthentication auth1 = new NtlmPasswordAuthentication("", outputFolderUserId, outputFolderPassword); //authenticating output folder
log.info("targetFilePath: {} and currentFile : {}", toFilePath, file);
SmbFile targetFile = new SmbFile(toFilePath, auth1);
try {
file.copyTo(targetFile);
file.delete(); //delete the file which we copied at our desired server
log.info("Archived File : {} to: {}", file.getName(), targetFile.getName());
return true;
} catch (SmbException e) {
log.error("Unable to Archive File: {}", file.getName());
return false;
}
} catch (MalformedURLException e) {
log.error("Connection failed to Server Drive: {}", toFilePath);
}
return false;
}
Happy to Help :)
Related
This spring app performs simple file upload,
here's the controller class
#Override
public String fileUpload(MultipartFile file) {
try{
// save uploaded image to images folder in root dir
Files.write(Paths.get("images/"+ file.getOriginalFilename()), file.getBytes());
// perform some tasks on image
return "";
} catch (IOException ioException) {
return "File upload has failed.";
} finally {
Files.delete(Paths.get("images/" + file.getOriginalFilename()));
}
}
but when i build jar and runs, it throws IOException saying,
java.nio.file.NoSuchFileException: images\8c9.jpeg.
So my question is how can i add the images folder inside the jar executable itself.
Thanks.
You should provide a full path for the images folder, or save in java.io.tmpdir creating the image folder first.
But, in my opinion you should configure your upload folder from a config file for flexibility. Take a look at this.
app:
profile-image:
upload-dir: C:\\projs\\web\\profile_image
file-types: jpg, JPG, png, PNG
width-height: 360, 360
max-size: 5242880
In your service or controller, do whatever you like, may be validate image type, size etc and process it as you like. For instance, if you want thumbnails(or avatar..).
In your controller or service class, get the directory:
#Value("${app.image-upload-dir:../images}")
private String imageUploadDir;
Finally,
public static Path uploadFileToPath(String fullFileName, String uploadDir, byte[] filecontent) throws IOException {
Path fileOut = null;
try{
Path fileAbsolutePath = Paths.get(StringUtils.join(uploadDir, File.separatorChar, fullFileName));
fileOut = Files.write(fileAbsolutePath, filecontent);
}catch (Exception e) {
throw e;
}
return fileOut; //full path of the file
}
For your question in the comment: You can use java.io.File.deleteOnExit() method, which deletes the file or directory defined by the abstract path name when the virtual machine terminates. TAKE A GOOD CARE THOUGH, it might leave some files if not handled properly.
try (ByteArrayOutputStream output = new ByteArrayOutputStream();){
URL fileUrl = new URL(url);
String tempDir = System.getProperty("java.io.tmpdir");
String path = tempDir + new Date().getTime() + ".jpg"; // note file extension
java.io.File file = new java.io.File(path);
file.deleteOnExit();
inputStream = fileUrl.openStream();
ByteStreams.copy(inputStream, output); // ByteStreams - Guava
outputStream = new FileOutputStream(file);
output.writeTo(outputStream);
outputStream.flush();
return file;
} catch (Exception e) {
throw e;
} finally {
try {
if(inputStream != null) {
inputStream.close();
}
if(outputStream != null) {
outputStream.close();
}
} catch(Exception e){
//skip
}
}
I have a function in an sdk where it strictly uses file from asset folder. I want to use the file from online. When I am passing the filename as example.mbtiles it is searching for the file is Asset folder and if found the app working fine. But when I am trying to get the file from a url such as www.myurl.com/example.mbtiles its taking all the url as string and finding the file in Asset folder which makes the app not working. Here is the function
private File getFile(String url, final Context context) {
if (context != null) {
//we assume asset here
AssetManager am = context.getAssets();
InputStream inputStream;
try {
inputStream = am.open(url);
final File mbTilesDir;
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
|| (!Environment.isExternalStorageRemovable())) {
mbTilesDir = new File(context.getExternalFilesDir(null), url);
} else {
mbTilesDir = new File(context.getFilesDir(), url);
}
return createFileFromInputStream(inputStream, mbTilesDir.getPath());
} catch (IOException e) {
Log.e(TAG, "MBTiles file not found in assets: " + e.toString());
return null;
}
}
try {
return new File(url);
} catch (Exception e) {
Log.e(TAG, "can't load MBTiles: " + e.toString());
return null;
}
}
How can I get the file from online url instead of local asset folder? what changes I need to do in this code? I also want to know, can I override this function in my MainActivity?
My web app is made on Spring MVC. I have a method where the user can upload PDFs
.
The I am sending the file as mutlipart file to the server. Every time the user uploads.
All what I want is to send the files as attachments in that email.
My code
private File prepareAttachment(final MultipartFile mFile) {
File file = new File(System.getProperty("java.io.tmpdir") + System.getProperty("file.separator") + mFile.getOriginalFilename());
try {
if(file.exists()) {
file.delete();
}
mFile.transferTo(file);
} catch (FileNotFoundException fnfE) {
file.delete();
LOG.error(" file was not found.", fnfE);
} catch (IOException ioE) {
file.delete();
LOG.error("file has failed to upload.", ioE);
}
return file;
}
calling the method to prepare the attachment:
MimeMessagePreparator preparator = new MimeMessagePreparator() {
#Override
public void prepare(final MimeMessage mimeMessage) throws Exception {
File file = prepareAttachment(form.getFile());
File file2 = prepareAttachment(form.getFile2());
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true);
message.addAttachment(form.getFile().getOriginalFilename(), file);
message.addAttachment(form.getFile2().getOriginalFilename(), file2);
Getting exception:
2017-08-28 15:10:59,549 ERROR com.menards.requestForms.business.service.EmailService - file has failed to upload.
java.io.IOException: Destination file [C:\opt\tcserver\main\temp] already exists and could not be deleted
at org.springframework.web.multipart.commons.CommonsMultipartFile.transferTo(CommonsMultipartFile.java:160) ~[spring-web-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at com.menards.requestForms.business.service.EmailService.prepareAttachment(EmailService.java:552) ~[classes/:?]
this will work perfectly if I comment out adding the second file :(
message.addAttachment(form.getFile2().getOriginalFilename(), file2);
any advise?
Generally, you shouldn't let your users determine the path of a file that you're creating on your server - it introduces a lot of security vulnerabilities. In this case, they may be attempting to create a temp file that has the same as some other file in your temp directory, potentially one that has nothing to do with your current application. File.createTempFile ensures that it creates a file with a unique name on each invocation.
It's also good practice to clean up temp files as soon as you're finished with them, so you don't have to worry about maintaining state on your server between method calls. This can sometimes create code that's a bit busy with catch/finally blocks, but it's worth it to avoid waking up at 3 AM to a hard disk that's full of garbage temp files.
I'd implement this roughly as:
private File prepareAttachment(final MultipartFile mFile) throws IOException {
File tmp = null;
try {
tmp = File.createTempFile("upload", ".tmp");
mFile.transferTo(tmp);
return tmp;
} catch (IOException ioE) {
if (tmp != null) {
tmp.delete();
}
LOG.error("file has failed to upload.", ioE);
throw ioE;
}
}
MimeMessagePreparator preparator = new MimeMessagePreparator() {
#Override
public void prepare(final MimeMessage mimeMessage) throws Exception {
File file1 = null;
File file2 = null;
try {
file1 = prepareAttachment(form.getFile());
file2 = prepareAttachment(form.getFile2());
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true);
message.addAttachment(form.getFile().getOriginalFilename(), file1);
message.addAttachment(form.getFile2().getOriginalFilename(), file2);
// do your other stuff
} catch (IOException e) {
// some sort of error-handling, probably returning a message with an error status
} finally {
if (file1 != null) {
file1.delete();
}
if (file2 != null) {
file2.delete();
}
}
}
};
I try to use the official Dropbox API for uploading a zip file to my account. My project is a desktop application (standard Java). My code looks like this:
public void uploadZipFile(File file) throws Exception {
FileInputStream fis = new FileInputStream(file);
try {
getClient(accessToken).uploadFile("/" + file.getName(), DbxWriteMode.add(), file.length(), fis);
} finally {
fis.close();
}
}
private DbxClient getClient(String accessToken) {
DbxRequestConfig dbxRequestConfig = new DbxRequestConfig(Constants.APP_NAME, Locale.getDefault().toString());
return new DbxClient(dbxRequestConfig, accessToken);
}
And I call it:
File zipFile = new File("C:\\Test\\MyFile.zip");
try {
uploadZipFile(zipFile);
} catch (Exception e) {
e.printStackTrace();
}
The file is transferred without any problems but then I want to delete the file after synchronization:
File zipFile = new File("C:\\Test\\MyFile.zip");
try {
uploadZipFile(zipFile);
System.out.println(zipFile.delete());
} catch (Exception e) {
e.printStackTrace();
}
The file is transferred successfully again, but the file still exists in the local file system and the delete method returns false.
there is a text file that an application produces, I would like to take that file and read it as strings in my application. How can I achieve that, any help would be grateful. Both applications are my applications so I can get the permissions.
Thank you!
This is possible using the standard android-storage, where all the user's files are stored too:
All you need to do is to access the same file and the same path in both applications, so e.g.:
String fileName = Environment.getExternalStorageDirectory().getPath() + "myFolderForBothApplications/myFileNameForBothApplications.txt";
Where myFolderForBothApplications and myFileNameForBothApplications can be replaced by your folder/filename, but this needs to be the same name in both applications.
Environment.getExternalStorageDirectory() returns a File-Object to the common, usable file-directory of the device, the same folder the user can see too.
By calling the getPath() method, a String representing the path to this storage is returned, so you can add your folder/filenames afterwards.
So a full code example would be:
String path = Environment.getExternalStorageDirectory().getPath() + "myFolderForBothApplications/";
String pathWithFile = path + "myFileNameForBothApplications.txt";
File dir = new File(path);
if(!dir.exists()) { //If the directory is not created yet
if(!dir.mkdirs()) { //try to create the directories to the given path, the method returns false if the directories could not be created
//Make some error-output here
return;
}
}
File file = new File(pathWithFile);
try {
f.createNewFile();
} catch (IOException e) {
e.printStackTrace();
//File couldn't be created
return;
}
Afterwards, you can write in the file or read from the file as provided e.g. in this answer.
Note that the file stored like this is visible for the user and my be edited / deleted by the user.
Also note what the JavaDoc for the getExternalStorageDirectory() says:
Return the primary external storage directory. This directory may not currently be accessible if it has been mounted by the user on their computer, has been removed from the device, or some other problem has happened. You can determine its current state with getExternalStorageState().
I do not know if this is the best/safest way to fix your problem, but it should work.
You can save the text file from your assets folder to anywhere in the sdcard, then you can read the file from the other application.
This method uses the getExternalFilesDir, that returns the absolute path to the directory on the primary shared/external storage device where the application can place persistent files it owns. These files are internal to the applications, and not typically visible to the user as media.
private void copyAssets() {
AssetManager assetManager = getAssets();
String[] files = null;
try {
files = assetManager.list("");
} catch (IOException e) {
Log.e("tag", "Failed to get asset file list.", e);
}
if (files != null) for (String filename : files) {
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(filename);
File outFile = new File(Environment.getExternalStorageDirectory(), filename);
out = new FileOutputStream(outFile);
copyFile(in, out);
} catch(IOException e) {
Log.e("tag", "Failed to copy asset file: " + filename, e);
}
finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
// NOOP
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
// NOOP
}
}
}
}
}
private void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while((read = in.read(buffer)) != -1){
out.write(buffer, 0, read);
}
}
And to read:
File dir = Environment.getExternalStorageDirectory();
File yourFile = new File(dir, "path/to/the/file/inside/the/sdcard.ext");